diff --git a/composer.json b/composer.json index d1ee000c4b3d0b4c45ca376cc5e1a483f0f74932..4ffa600e20fb4070a37d2680a7574969e14e313d 100644 --- a/composer.json +++ b/composer.json @@ -10,8 +10,7 @@ "require": { "drupal/autocomplete_id": "^1.5", "drupal/charts": "^5.0", - "drupal/core": "^9 || ^10 || ^11", - "drupal/field_group": "^3.4", + "drupal/core": "^10 || ^11", "drupal/moderation_note": "^1.0-beta5", "drupal/search_api": "^1.0", "drupal/token": "^1.13", diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_correct_template.yml b/config/install/field.field.knowledge_competency.knowledge_competency.field_correct_template.yml deleted file mode 100644 index bf42be990ca2452f1c4d61fda79e9cfa30704018..0000000000000000000000000000000000000000 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_correct_template.yml +++ /dev/null @@ -1,23 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.knowledge_competency.field_correct_template - module: - - knowledge -id: knowledge_competency.knowledge_competency.field_correct_template -field_name: field_correct_template -entity_type: knowledge_competency -bundle: knowledge_competency -label: 'Correct Template' -description: 'Understands Solve Loop templates and, given a request, can select the correct one' -required: false -translatable: false -default_value: - - - value: 0 -default_value_callback: '' -settings: - on_label: 'Yes' - off_label: 'No' -field_type: boolean diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_note.yml b/config/install/field.field.knowledge_competency.knowledge_competency.field_note.yml deleted file mode 100644 index d422e35cfa73320ef98e7b3d852e64834597e6c4..0000000000000000000000000000000000000000 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_note.yml +++ /dev/null @@ -1,20 +0,0 @@ -langcode: en -status: true -dependencies: - config: - - field.storage.knowledge_competency.field_note - module: - - knowledge - - text -id: knowledge_competency.knowledge_competency.field_note -field_name: field_note -entity_type: knowledge_competency -bundle: knowledge_competency -label: Note -description: '' -required: false -translatable: false -default_value: { } -default_value_callback: '' -settings: { } -field_type: text_long diff --git a/config/install/field.field.user.user.knowledge_coach.yml b/config/install/field.field.user.user.knowledge_coach.yml new file mode 100644 index 0000000000000000000000000000000000000000..bbdebbe30fed55730f1c4ac856a28eb6c78a3f34 --- /dev/null +++ b/config/install/field.field.user.user.knowledge_coach.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.user.knowledge_coach + module: + - user +id: user.user.knowledge_coach +field_name: knowledge_coach +entity_type: user +bundle: user +label: Coach +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:user' + handler_settings: + target_bundles: null + sort: + field: _none + direction: ASC + auto_create: false + filter: + type: _none + include_anonymous: false +field_type: entity_reference diff --git a/config/install/field.field.user.user.knowledge_leader.yml b/config/install/field.field.user.user.knowledge_leader.yml new file mode 100644 index 0000000000000000000000000000000000000000..561a5dde5d1f901b85efa1f3e62ab1746ae7e8d3 --- /dev/null +++ b/config/install/field.field.user.user.knowledge_leader.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.user.knowledge_leader + module: + - user +id: user.user.knowledge_leader +field_name: knowledge_leader +entity_type: user +bundle: user +label: Leader +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:user' + handler_settings: + target_bundles: null + sort: + field: _none + direction: ASC + auto_create: false + filter: + type: _none + include_anonymous: false +field_type: entity_reference diff --git a/config/install/field.storage.knowledge_competency.field_correct_template.yml b/config/install/field.storage.knowledge_competency.field_correct_template.yml deleted file mode 100644 index 4a4429a2bc8fa8f70a4c6a69683a4a1ee4716399..0000000000000000000000000000000000000000 --- a/config/install/field.storage.knowledge_competency.field_correct_template.yml +++ /dev/null @@ -1,17 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - knowledge -id: knowledge_competency.field_correct_template -field_name: field_correct_template -entity_type: knowledge_competency -type: boolean -settings: { } -module: core -locked: false -cardinality: 1 -translatable: true -indexes: { } -persist_with_no_fields: false -custom_storage: false diff --git a/config/install/field.storage.knowledge_competency.field_note.yml b/config/install/field.storage.knowledge_competency.field_note.yml deleted file mode 100644 index a4136c886e531021f9bc46e8550087358ebbb530..0000000000000000000000000000000000000000 --- a/config/install/field.storage.knowledge_competency.field_note.yml +++ /dev/null @@ -1,18 +0,0 @@ -langcode: en -status: true -dependencies: - module: - - knowledge - - text -id: knowledge_competency.field_note -field_name: field_note -entity_type: knowledge_competency -type: text_long -settings: { } -module: text -locked: false -cardinality: 1 -translatable: true -indexes: { } -persist_with_no_fields: false -custom_storage: false diff --git a/config/install/knowledge.competency.settings.yml b/config/install/knowledge.competency.settings.yml new file mode 100644 index 0000000000000000000000000000000000000000..239cc478bfdf9013535e69d05211a33281218e3a --- /dev/null +++ b/config/install/knowledge.competency.settings.yml @@ -0,0 +1,16 @@ +roles: + - + role: knowledge_candidate + weight: 0 + action: auto + promote: self + - + role: knowledge_contributor + weight: 1 + action: auto + promote: self + - + role: knowledge_publisher + weight: 2 + action: auto + promote: self diff --git a/config/install/user.role.knowledge_leader.yml b/config/install/user.role.knowledge_leader.yml new file mode 100644 index 0000000000000000000000000000000000000000..b6e8fa8e415574a5c97dcc596687b5e29e6c4855 --- /dev/null +++ b/config/install/user.role.knowledge_leader.yml @@ -0,0 +1,11 @@ +langcode: en +status: true +dependencies: + enforced: + module: + - knowledge +id: knowledge_leader +label: Leader +weight: 7 +is_admin: null +permissions: {} diff --git a/config/optional/core.entity_form_display.knowledge_competency.knowledge_competency.default.yml b/config/optional/core.entity_form_display.knowledge_competency.knowledge_competency.default.yml new file mode 100644 index 0000000000000000000000000000000000000000..714b35c3b77d3d5daea0802b3a163df7be918723 --- /dev/null +++ b/config/optional/core.entity_form_display.knowledge_competency.knowledge_competency.default.yml @@ -0,0 +1,212 @@ +langcode: en +status: true +dependencies: + config: + - field.field.knowledge_competency.knowledge_competency.field_audience + - field.field.knowledge_competency.knowledge_competency.field_business + - field.field.knowledge_competency.knowledge_competency.field_capture_context + - field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment + - field.field.knowledge_competency.knowledge_competency.field_collaborate + - field.field.knowledge_competency.knowledge_competency.field_complete_thoughts + - field.field.knowledge_competency.knowledge_competency.field_confidence + - field.field.knowledge_competency.knowledge_competency.field_content_standard + - field.field.knowledge_competency.knowledge_competency.field_documents_request + - field.field.knowledge_competency.knowledge_competency.field_fix_it + - field.field.knowledge_competency.knowledge_competency.field_flag_it + - field.field.knowledge_competency.knowledge_competency.field_improve + - field.field.knowledge_competency.knowledge_competency.field_includes_context + - field.field.knowledge_competency.knowledge_competency.field_iterative_search + - field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements + - field.field.knowledge_competency.knowledge_competency.field_link_it + - field.field.knowledge_competency.knowledge_competency.field_one + - field.field.knowledge_competency.knowledge_competency.field_process_adherence + - field.field.knowledge_competency.knowledge_competency.field_relevant + - field.field.knowledge_competency.knowledge_competency.field_reuse + - field.field.knowledge_competency.knowledge_competency.field_search_it + - field.field.knowledge_competency.knowledge_competency.field_solve_loop + - field.field.knowledge_competency.knowledge_competency.field_structure + - field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve + - field.field.knowledge_competency.knowledge_competency.field_update_or_create + module: + - knowledge +id: knowledge_competency.knowledge_competency.default +targetEntityType: knowledge_competency +bundle: knowledge_competency +mode: default +content: + field_audience: + type: boolean_checkbox + weight: 15 + region: content + settings: + display_label: true + third_party_settings: { } + field_business: + type: boolean_checkbox + weight: 3 + region: content + settings: + display_label: true + third_party_settings: { } + field_capture_context: + type: boolean_checkbox + weight: 14 + region: content + settings: + display_label: true + third_party_settings: { } + field_capture_in_the_moment: + type: boolean_checkbox + weight: 23 + region: content + settings: + display_label: true + third_party_settings: { } + field_collaborate: + type: boolean_checkbox + weight: 24 + region: content + settings: + display_label: true + third_party_settings: { } + field_complete_thoughts: + type: boolean_checkbox + weight: 9 + region: content + settings: + display_label: true + third_party_settings: { } + field_confidence: + type: boolean_checkbox + weight: 22 + region: content + settings: + display_label: true + third_party_settings: { } + field_content_standard: + type: boolean_checkbox + weight: 16 + region: content + settings: + display_label: true + third_party_settings: { } + field_documents_request: + type: boolean_checkbox + weight: 4 + region: content + settings: + display_label: true + third_party_settings: { } + field_fix_it: + type: boolean_checkbox + weight: 5 + region: content + settings: + display_label: true + third_party_settings: { } + field_flag_it: + type: boolean_checkbox + weight: 2 + region: content + settings: + display_label: true + third_party_settings: { } + field_improve: + type: boolean_checkbox + weight: 20 + region: content + settings: + display_label: true + third_party_settings: { } + field_includes_context: + type: boolean_checkbox + weight: 11 + region: content + settings: + display_label: true + third_party_settings: { } + field_iterative_search: + type: boolean_checkbox + weight: 19 + region: content + settings: + display_label: true + third_party_settings: { } + field_kcs_article_elements: + type: boolean_checkbox + weight: 7 + region: content + settings: + display_label: true + third_party_settings: { } + field_link_it: + type: boolean_checkbox + weight: 1 + region: content + settings: + display_label: true + third_party_settings: { } + field_one: + type: boolean_checkbox + weight: 10 + region: content + settings: + display_label: true + third_party_settings: { } + field_process_adherence: + type: boolean_checkbox + weight: 21 + region: content + settings: + display_label: true + third_party_settings: { } + field_relevant: + type: boolean_checkbox + weight: 18 + region: content + settings: + display_label: true + third_party_settings: { } + field_reuse: + type: boolean_checkbox + weight: 6 + region: content + settings: + display_label: true + third_party_settings: { } + field_search_it: + type: boolean_checkbox + weight: 0 + region: content + settings: + display_label: true + third_party_settings: { } + field_solve_loop: + type: boolean_checkbox + weight: 13 + region: content + settings: + display_label: true + third_party_settings: { } + field_structure: + type: boolean_checkbox + weight: 8 + region: content + settings: + display_label: true + third_party_settings: { } + field_sufficient_to_solve: + type: boolean_checkbox + weight: 17 + region: content + settings: + display_label: true + third_party_settings: { } + field_update_or_create: + type: boolean_checkbox + weight: 12 + region: content + settings: + display_label: true + third_party_settings: { } +hidden: { } diff --git a/config/optional/core.entity_view_display.knowledge_competency.knowledge_competency.default.yml b/config/optional/core.entity_view_display.knowledge_competency.knowledge_competency.default.yml new file mode 100644 index 0000000000000000000000000000000000000000..1ab395f916809334a918fcddd97dfb94ca6b82b6 --- /dev/null +++ b/config/optional/core.entity_view_display.knowledge_competency.knowledge_competency.default.yml @@ -0,0 +1,298 @@ +langcode: en +status: true +dependencies: + config: + - field.field.knowledge_competency.knowledge_competency.field_audience + - field.field.knowledge_competency.knowledge_competency.field_business + - field.field.knowledge_competency.knowledge_competency.field_capture_context + - field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment + - field.field.knowledge_competency.knowledge_competency.field_collaborate + - field.field.knowledge_competency.knowledge_competency.field_complete_thoughts + - field.field.knowledge_competency.knowledge_competency.field_confidence + - field.field.knowledge_competency.knowledge_competency.field_content_standard + - field.field.knowledge_competency.knowledge_competency.field_documents_request + - field.field.knowledge_competency.knowledge_competency.field_fix_it + - field.field.knowledge_competency.knowledge_competency.field_flag_it + - field.field.knowledge_competency.knowledge_competency.field_improve + - field.field.knowledge_competency.knowledge_competency.field_includes_context + - field.field.knowledge_competency.knowledge_competency.field_iterative_search + - field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements + - field.field.knowledge_competency.knowledge_competency.field_link_it + - field.field.knowledge_competency.knowledge_competency.field_one + - field.field.knowledge_competency.knowledge_competency.field_process_adherence + - field.field.knowledge_competency.knowledge_competency.field_relevant + - field.field.knowledge_competency.knowledge_competency.field_reuse + - field.field.knowledge_competency.knowledge_competency.field_search_it + - field.field.knowledge_competency.knowledge_competency.field_solve_loop + - field.field.knowledge_competency.knowledge_competency.field_structure + - field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve + - field.field.knowledge_competency.knowledge_competency.field_update_or_create + module: + - knowledge +id: knowledge_competency.knowledge_competency.default +targetEntityType: knowledge_competency +bundle: knowledge_competency +mode: default +content: + field_audience: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 15 + region: content + field_business: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 3 + region: content + field_capture_context: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 14 + region: content + field_capture_in_the_moment: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 23 + region: content + field_collaborate: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 24 + region: content + field_complete_thoughts: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 9 + region: content + field_confidence: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 22 + region: content + field_content_standard: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 16 + region: content + field_documents_request: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 4 + region: content + field_fix_it: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 5 + region: content + field_flag_it: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 2 + region: content + field_improve: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 20 + region: content + field_includes_context: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 11 + region: content + field_iterative_search: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 19 + region: content + field_kcs_article_elements: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 7 + region: content + field_link_it: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 1 + region: content + field_one: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 10 + region: content + field_process_adherence: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 21 + region: content + field_relevant: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 18 + region: content + field_reuse: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 6 + region: content + field_search_it: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 0 + region: content + field_solve_loop: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 13 + region: content + field_structure: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 8 + region: content + field_sufficient_to_solve: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 17 + region: content + field_update_or_create: + type: knowledge_competency + label: inline + settings: + format: default + format_custom_false: '' + format_custom_true: '' + third_party_settings: { } + weight: 12 + region: content +hidden: + contributor_approved: true + contributor_coach: true + contributor_leader: true + contributor_proposed: true + publisher_approved: true + publisher_coach: true + publisher_leader: true + publisher_proposed: true + roles: true + search_api_excerpt: true + user_id: true diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_audience.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_audience.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_audience.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_audience.yml index ce1496876deeda35976e5f5076ad009cb4c5966e..385a76e31d57c2d987d5cd398fdc7ba4baf87f7f 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_audience.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_audience.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_audience module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_audience field_name: field_audience entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_business.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_business.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_business.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_business.yml index 80871a79bf8d663aedef28ef532872ea34c5d74a..9b9194dce83c0543e33c96793396236fd0760907 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_business.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_business.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_business module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_business field_name: field_business entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_capture_context.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_capture_context.yml similarity index 74% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_capture_context.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_capture_context.yml index 767b9599b3137a213ce3a0aaa44cc6d7732e48f9..f6e8f148c51170332fc4a3cf0f99b7a6418f62e3 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_capture_context.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_capture_context.yml @@ -5,12 +5,15 @@ dependencies: - field.storage.knowledge_competency.field_capture_context module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_capture_context field_name: field_capture_context entity_type: knowledge_competency bundle: knowledge_competency label: 'Capture Context' -description: 'Consistently demonstrates the ability to capture the requestor''s context' +description: "Consistently demonstrates the ability to capture the requestor's context" required: false translatable: false default_value: diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment.yml similarity index 90% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment.yml index 730f6c5424c59e3f92ee4f13a2a83da1554f7b26..0e6dca6916bdc1f30824ceb32f6abb191a16c000 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_capture_in_the_moment.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_capture_in_the_moment module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_capture_in_the_moment field_name: field_capture_in_the_moment entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_collaborate.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_collaborate.yml similarity index 88% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_collaborate.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_collaborate.yml index cdf1d9a67d8fc5ea042f94711055f3b82c6eb4a0..882a9725834e685e532a0bbcabbdf8075e63038d 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_collaborate.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_collaborate.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_collaborate module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_collaborate field_name: field_collaborate entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_complete_thoughts.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_complete_thoughts.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_complete_thoughts.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_complete_thoughts.yml index f98cd3692c44e14e2c1367f09f7f164c9e501ffa..9c1f5fcd60c7f97ec4ab42e76b7df7ac11b2f413 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_complete_thoughts.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_complete_thoughts.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_complete_thoughts module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_complete_thoughts field_name: field_complete_thoughts entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_confidence.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_confidence.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_confidence.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_confidence.yml index a7b5a5b693840430ca60d4ad929a92a8738ea64d..4ce7751826dcaddc219e8e2634c01373f227ae7f 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_confidence.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_confidence.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_confidence module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_confidence field_name: field_confidence entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_content_standard.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_content_standard.yml similarity index 89% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_content_standard.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_content_standard.yml index 3cc18d5de132f0e22ca68e10b817df2d313e8df2..1a53a01a5269ebc661b80ba07c0486a2f84602d3 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_content_standard.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_content_standard.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_content_standard module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_content_standard field_name: field_content_standard entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_documents_request.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_documents_request.yml similarity index 88% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_documents_request.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_documents_request.yml index 1dc1c68e96fca0e74cc73c3aa7f0d0ee41503132..f197fbfa6f0b1f653d51592eedc41b11eff510b3 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_documents_request.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_documents_request.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_documents_request module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_documents_request field_name: field_documents_request entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_fix_it.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_fix_it.yml similarity index 88% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_fix_it.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_fix_it.yml index e6bfbd9f495926ae90b190a936e8618381b72c6b..3d8b2e85c6cb1e2226ef38f4ba6481bd8d74065c 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_fix_it.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_fix_it.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_fix_it module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_fix_it field_name: field_fix_it entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_flag_it.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_flag_it.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_flag_it.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_flag_it.yml index 0552f5519562cc8b565d740d066ff200ac536fd3..d7aa78cb5edb9150f84bda97a09dcb9c603c7503 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_flag_it.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_flag_it.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_flag_it module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_candidate id: knowledge_competency.knowledge_competency.field_flag_it field_name: field_flag_it entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_improve.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_improve.yml similarity index 88% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_improve.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_improve.yml index 27348da89a9a218c43d03f9c4ecc1a45df728cee..be3c6d9cf40ffd0db7ef31f6429919fce282a30e 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_improve.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_improve.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_improve module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_improve field_name: field_improve entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_includes_context.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_includes_context.yml similarity index 79% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_includes_context.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_includes_context.yml index 7f89c567676ecaa56897aa2a4bd4773635e437e4..4be4fb30d7588f251a597147d4da18fe5a943089 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_includes_context.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_includes_context.yml @@ -5,12 +5,15 @@ dependencies: - field.storage.knowledge_competency.field_includes_context module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_includes_context field_name: field_includes_context entity_type: knowledge_competency bundle: knowledge_competency label: 'Includes Context' -description: 'Includes the requestor''s context' +description: "Includes the requestor's context" required: false translatable: false default_value: diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_iterative_search.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_iterative_search.yml similarity index 69% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_iterative_search.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_iterative_search.yml index c5ea7db364e6df2efa07e17f13ecad4017cc0a16..103e970cccf39e6225e49d1585036203d92cc86c 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_iterative_search.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_iterative_search.yml @@ -5,12 +5,15 @@ dependencies: - field.storage.knowledge_competency.field_iterative_search module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_iterative_search field_name: field_iterative_search entity_type: knowledge_competency bundle: knowledge_competency label: 'Iterative Search' -description: 'Effectively and iteratively searches using the requestor''s context and additional information gathered during the interaction' +description: "Effectively and iteratively searches using the requestor's context and additional information gathered during the interaction" required: false translatable: false default_value: diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements.yml similarity index 88% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements.yml index 4738b7815a37c06b65e9c3f363ae26e5e8ae7333..8f1e258029a46fae4e472d504c677ad9465cdb80 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_kcs_article_elements.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_kcs_article_elements module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_kcs_article_elements field_name: field_kcs_article_elements entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_link_it.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_link_it.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_link_it.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_link_it.yml index e5a917ec99b85b132251a190ccbb56bb05be83cf..f8ac4611dd9a8e19603823a9cd2e0115f89ed0d3 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_link_it.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_link_it.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_link_it module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_candidate id: knowledge_competency.knowledge_competency.field_link_it field_name: field_link_it entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_one.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_one.yml similarity index 85% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_one.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_one.yml index 83e602b75ad870012339993d3505a96d60172271..0ffd14e29044f054e7127f8a84ad838d2fe256b9 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_one.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_one.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_one module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_one field_name: field_one entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_process_adherence.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_process_adherence.yml similarity index 89% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_process_adherence.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_process_adherence.yml index 6562e48fcf6b79335272102c4a9c700682c1f134..58badd8ff5e160c20c721de26e05def1a0e51d76 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_process_adherence.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_process_adherence.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_process_adherence module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_process_adherence field_name: field_process_adherence entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_relevant.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_relevant.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_relevant.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_relevant.yml index f4298a956b7c0cfe86f75567ceadf3cafc538342..b0475da7308769d4b81cdb965863ab2c22b3863b 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_relevant.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_relevant.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_relevant module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_relevant field_name: field_relevant entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_reuse.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_reuse.yml similarity index 87% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_reuse.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_reuse.yml index 8599a8d79e7680d798568eb4b646891aa9d04e61..4bd3bffc9f68b6225bcb3483e0de1c323f03c3db 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_reuse.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_reuse.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_reuse module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_reuse field_name: field_reuse entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_search_it.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_search_it.yml similarity index 88% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_search_it.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_search_it.yml index eb6d2049955e3841cc5de2c7f92a7363f88b64cf..c0616a686e4d866cb3bdd88383be181e2c5c2c5f 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_search_it.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_search_it.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_search_it module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_candidate id: knowledge_competency.knowledge_competency.field_search_it field_name: field_search_it entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_solve_loop.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_solve_loop.yml similarity index 88% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_solve_loop.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_solve_loop.yml index 2ed6f537b68b7e544376e1d04fc39ad1a0231f5f..9e34fa52c29508832c82b849e82c5ee91665eba9 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_solve_loop.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_solve_loop.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_solve_loop module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_solve_loop field_name: field_solve_loop entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_structure.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_structure.yml similarity index 86% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_structure.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_structure.yml index f99548533725aeb994c4ad0df45f874f8621bd13..5a1d18443f9f099d4bcba68acbec10560fe76a4a 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_structure.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_structure.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_structure module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_structure field_name: field_structure entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve.yml similarity index 89% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve.yml index c36b7648d96e0b7b0d06119eda02ec7fb859034b..eb78bf4d4610280ffad692dc8960807fd80e4a21 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_sufficient_to_solve.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_sufficient_to_solve module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_publisher id: knowledge_competency.knowledge_competency.field_sufficient_to_solve field_name: field_sufficient_to_solve entity_type: knowledge_competency diff --git a/config/install/field.field.knowledge_competency.knowledge_competency.field_update_or_create.yml b/config/optional/field.field.knowledge_competency.knowledge_competency.field_update_or_create.yml similarity index 89% rename from config/install/field.field.knowledge_competency.knowledge_competency.field_update_or_create.yml rename to config/optional/field.field.knowledge_competency.knowledge_competency.field_update_or_create.yml index f20bce6a75a2a86eb5f488d451d7beecbe0d5a6c..ae789c3fb238499bd9ee0d2614c2cf91839c0805 100644 --- a/config/install/field.field.knowledge_competency.knowledge_competency.field_update_or_create.yml +++ b/config/optional/field.field.knowledge_competency.knowledge_competency.field_update_or_create.yml @@ -5,6 +5,9 @@ dependencies: - field.storage.knowledge_competency.field_update_or_create module: - knowledge +third_party_settings: + knowledge: + competency_role: knowledge_contributor id: knowledge_competency.knowledge_competency.field_update_or_create field_name: field_update_or_create entity_type: knowledge_competency diff --git a/config/install/field.storage.knowledge_competency.field_audience.yml b/config/optional/field.storage.knowledge_competency.field_audience.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_audience.yml rename to config/optional/field.storage.knowledge_competency.field_audience.yml diff --git a/config/install/field.storage.knowledge_competency.field_business.yml b/config/optional/field.storage.knowledge_competency.field_business.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_business.yml rename to config/optional/field.storage.knowledge_competency.field_business.yml diff --git a/config/install/field.storage.knowledge_competency.field_capture_context.yml b/config/optional/field.storage.knowledge_competency.field_capture_context.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_capture_context.yml rename to config/optional/field.storage.knowledge_competency.field_capture_context.yml diff --git a/config/install/field.storage.knowledge_competency.field_capture_in_the_moment.yml b/config/optional/field.storage.knowledge_competency.field_capture_in_the_moment.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_capture_in_the_moment.yml rename to config/optional/field.storage.knowledge_competency.field_capture_in_the_moment.yml diff --git a/config/install/field.storage.knowledge_competency.field_collaborate.yml b/config/optional/field.storage.knowledge_competency.field_collaborate.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_collaborate.yml rename to config/optional/field.storage.knowledge_competency.field_collaborate.yml diff --git a/config/install/field.storage.knowledge_competency.field_complete_thoughts.yml b/config/optional/field.storage.knowledge_competency.field_complete_thoughts.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_complete_thoughts.yml rename to config/optional/field.storage.knowledge_competency.field_complete_thoughts.yml diff --git a/config/install/field.storage.knowledge_competency.field_confidence.yml b/config/optional/field.storage.knowledge_competency.field_confidence.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_confidence.yml rename to config/optional/field.storage.knowledge_competency.field_confidence.yml diff --git a/config/install/field.storage.knowledge_competency.field_content_standard.yml b/config/optional/field.storage.knowledge_competency.field_content_standard.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_content_standard.yml rename to config/optional/field.storage.knowledge_competency.field_content_standard.yml diff --git a/config/install/field.storage.knowledge_competency.field_documents_request.yml b/config/optional/field.storage.knowledge_competency.field_documents_request.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_documents_request.yml rename to config/optional/field.storage.knowledge_competency.field_documents_request.yml diff --git a/config/install/field.storage.knowledge_competency.field_fix_it.yml b/config/optional/field.storage.knowledge_competency.field_fix_it.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_fix_it.yml rename to config/optional/field.storage.knowledge_competency.field_fix_it.yml diff --git a/config/install/field.storage.knowledge_competency.field_flag_it.yml b/config/optional/field.storage.knowledge_competency.field_flag_it.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_flag_it.yml rename to config/optional/field.storage.knowledge_competency.field_flag_it.yml diff --git a/config/install/field.storage.knowledge_competency.field_improve.yml b/config/optional/field.storage.knowledge_competency.field_improve.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_improve.yml rename to config/optional/field.storage.knowledge_competency.field_improve.yml diff --git a/config/install/field.storage.knowledge_competency.field_includes_context.yml b/config/optional/field.storage.knowledge_competency.field_includes_context.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_includes_context.yml rename to config/optional/field.storage.knowledge_competency.field_includes_context.yml diff --git a/config/install/field.storage.knowledge_competency.field_iterative_search.yml b/config/optional/field.storage.knowledge_competency.field_iterative_search.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_iterative_search.yml rename to config/optional/field.storage.knowledge_competency.field_iterative_search.yml diff --git a/config/install/field.storage.knowledge_competency.field_kcs_article_elements.yml b/config/optional/field.storage.knowledge_competency.field_kcs_article_elements.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_kcs_article_elements.yml rename to config/optional/field.storage.knowledge_competency.field_kcs_article_elements.yml diff --git a/config/install/field.storage.knowledge_competency.field_link_it.yml b/config/optional/field.storage.knowledge_competency.field_link_it.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_link_it.yml rename to config/optional/field.storage.knowledge_competency.field_link_it.yml diff --git a/config/install/field.storage.knowledge_competency.field_one.yml b/config/optional/field.storage.knowledge_competency.field_one.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_one.yml rename to config/optional/field.storage.knowledge_competency.field_one.yml diff --git a/config/install/field.storage.knowledge_competency.field_process_adherence.yml b/config/optional/field.storage.knowledge_competency.field_process_adherence.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_process_adherence.yml rename to config/optional/field.storage.knowledge_competency.field_process_adherence.yml diff --git a/config/install/field.storage.knowledge_competency.field_relevant.yml b/config/optional/field.storage.knowledge_competency.field_relevant.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_relevant.yml rename to config/optional/field.storage.knowledge_competency.field_relevant.yml diff --git a/config/install/field.storage.knowledge_competency.field_reuse.yml b/config/optional/field.storage.knowledge_competency.field_reuse.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_reuse.yml rename to config/optional/field.storage.knowledge_competency.field_reuse.yml diff --git a/config/install/field.storage.knowledge_competency.field_search_it.yml b/config/optional/field.storage.knowledge_competency.field_search_it.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_search_it.yml rename to config/optional/field.storage.knowledge_competency.field_search_it.yml diff --git a/config/install/field.storage.knowledge_competency.field_solve_loop.yml b/config/optional/field.storage.knowledge_competency.field_solve_loop.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_solve_loop.yml rename to config/optional/field.storage.knowledge_competency.field_solve_loop.yml diff --git a/config/install/field.storage.knowledge_competency.field_structure.yml b/config/optional/field.storage.knowledge_competency.field_structure.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_structure.yml rename to config/optional/field.storage.knowledge_competency.field_structure.yml diff --git a/config/install/field.storage.knowledge_competency.field_sufficient_to_solve.yml b/config/optional/field.storage.knowledge_competency.field_sufficient_to_solve.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_sufficient_to_solve.yml rename to config/optional/field.storage.knowledge_competency.field_sufficient_to_solve.yml diff --git a/config/install/field.storage.knowledge_competency.field_update_or_create.yml b/config/optional/field.storage.knowledge_competency.field_update_or_create.yml similarity index 100% rename from config/install/field.storage.knowledge_competency.field_update_or_create.yml rename to config/optional/field.storage.knowledge_competency.field_update_or_create.yml diff --git a/config/install/field.storage.node.knowledge.yml b/config/optional/field.storage.node.knowledge.yml similarity index 100% rename from config/install/field.storage.node.knowledge.yml rename to config/optional/field.storage.node.knowledge.yml diff --git a/config/install/field.storage.node.knowledge_audience.yml b/config/optional/field.storage.node.knowledge_audience.yml similarity index 100% rename from config/install/field.storage.node.knowledge_audience.yml rename to config/optional/field.storage.node.knowledge_audience.yml diff --git a/config/install/field.storage.node.knowledge_governance.yml b/config/optional/field.storage.node.knowledge_governance.yml similarity index 100% rename from config/install/field.storage.node.knowledge_governance.yml rename to config/optional/field.storage.node.knowledge_governance.yml diff --git a/config/install/field.storage.node.knowledge_governance_user.yml b/config/optional/field.storage.node.knowledge_governance_user.yml similarity index 100% rename from config/install/field.storage.node.knowledge_governance_user.yml rename to config/optional/field.storage.node.knowledge_governance_user.yml diff --git a/config/install/field.storage.node.knowledge_governance_user_role.yml b/config/optional/field.storage.node.knowledge_governance_user_role.yml similarity index 100% rename from config/install/field.storage.node.knowledge_governance_user_role.yml rename to config/optional/field.storage.node.knowledge_governance_user_role.yml diff --git a/config/optional/views.view.knowledge_competency_progress.yml b/config/optional/views.view.knowledge_competency_progress.yml new file mode 100644 index 0000000000000000000000000000000000000000..b5958121e214d570c2aa8ebebcdee727a4dcf06d --- /dev/null +++ b/config/optional/views.view.knowledge_competency_progress.yml @@ -0,0 +1,1945 @@ +langcode: en +status: true +dependencies: + module: + - knowledge +id: knowledge_competency_progress +label: 'Competency Progress' +module: views +description: 'The overall progress' +tag: '' +base_table: knowledge_competency +base_field: id +display: + default: + id: default + display_title: Default + display_plugin: default + position: 0 + display_options: + fields: + id: + id: id + table: knowledge_competency + field: id + relationship: none + group_type: count + admin_label: '' + entity_type: knowledge_competency + entity_field: id + plugin_id: field + label: Total + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: number_integer + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_search_it: + id: field_search_it + table: knowledge_competency__field_search_it + field: field_search_it + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Search + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: default + format_custom_false: '' + format_custom_true: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_link_it: + id: field_link_it + table: knowledge_competency__field_link_it + field: field_link_it + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Link + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: default + format_custom_false: '' + format_custom_true: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_flag_it: + id: field_flag_it + table: knowledge_competency__field_flag_it + field: field_flag_it + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Flag + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: default + format_custom_false: '' + format_custom_true: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_business: + id: field_business + table: knowledge_competency__field_business + field: field_business + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Business + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_documents_request: + id: field_documents_request + table: knowledge_competency__field_documents_request + field: field_documents_request + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Documents request' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_fix_it: + id: field_fix_it + table: knowledge_competency__field_fix_it + field: field_fix_it + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Fix + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_reuse: + id: field_reuse + table: knowledge_competency__field_reuse + field: field_reuse + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Reuse + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_correct_template: + id: field_correct_template + table: knowledge_competency__field_correct_template + field: field_correct_template + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Correct Template' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_kcs_article_elements: + id: field_kcs_article_elements + table: knowledge_competency__field_kcs_article_elements + field: field_kcs_article_elements + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Article Elements' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_structure: + id: field_structure + table: knowledge_competency__field_structure + field: field_structure + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Structure + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_complete_thoughts: + id: field_complete_thoughts + table: knowledge_competency__field_complete_thoughts + field: field_complete_thoughts + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Complete thoughts' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_one: + id: field_one + table: knowledge_competency__field_one + field: field_one + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'One thing' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_includes_context: + id: field_includes_context + table: knowledge_competency__field_includes_context + field: field_includes_context + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Includes Context' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_update_or_create: + id: field_update_or_create + table: knowledge_competency__field_update_or_create + field: field_update_or_create + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Update or create' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_solve_loop: + id: field_solve_loop + table: knowledge_competency__field_solve_loop + field: field_solve_loop + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Solve Loop' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_audience: + id: field_audience + table: knowledge_competency__field_audience + field: field_audience + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Audience + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_capture_context: + id: field_capture_context + table: knowledge_competency__field_capture_context + field: field_capture_context + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Capture Context' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_capture_in_the_moment: + id: field_capture_in_the_moment + table: knowledge_competency__field_capture_in_the_moment + field: field_capture_in_the_moment + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Capture in the moment' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_collaborate: + id: field_collaborate + table: knowledge_competency__field_collaborate + field: field_collaborate + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Collaborate + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_confidence: + id: field_confidence + table: knowledge_competency__field_confidence + field: field_confidence + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Confidence + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_content_standard: + id: field_content_standard + table: knowledge_competency__field_content_standard + field: field_content_standard + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Content Standard' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_improve: + id: field_improve + table: knowledge_competency__field_improve + field: field_improve + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Improve + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_iterative_search: + id: field_iterative_search + table: knowledge_competency__field_iterative_search + field: field_iterative_search + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Iterative Search' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_process_adherence: + id: field_process_adherence + table: knowledge_competency__field_process_adherence + field: field_process_adherence + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Process Adherence' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_relevant: + id: field_relevant + table: knowledge_competency__field_relevant + field: field_relevant + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: Relevant + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + field_sufficient_to_solve: + id: field_sufficient_to_solve + table: knowledge_competency__field_sufficient_to_solve + field: field_sufficient_to_solve + relationship: none + group_type: sum + admin_label: '' + plugin_id: field + label: 'Sufficient to solve' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: { } + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: '' + field_api_classes: false + set_precision: false + precision: 0 + decimal: . + format_plural: 0 + format_plural_string: !!binary MQNAY291bnQ= + prefix: '' + suffix: '' + pager: + type: none + options: + offset: 0 + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + access: + type: none + options: { } + cache: + type: tag + options: { } + empty: { } + sorts: { } + arguments: { } + filters: { } + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + columns: + link_to_latest_version: link_to_latest_version + default: '-1' + info: + link_to_latest_version: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + override: true + sticky: false + summary: '' + empty_table: false + caption: '' + description: '' + row: + type: fields + options: + default_field_elements: true + inline: { } + separator: '' + hide_empty: false + query: + type: views_query + options: + query_comment: '' + disable_sql_rewrite: false + distinct: false + replica: false + query_tags: { } + relationships: { } + group_by: true + header: { } + footer: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_interface' + tags: { } diff --git a/config/schema/knowledge.schema.yml b/config/schema/knowledge.schema.yml index 6dd02d06756e48b5ff30e305bd0d731c8c5567a4..1710f3f3d25f5517751917dd68b7cc899c5f97b1 100644 --- a/config/schema/knowledge.schema.yml +++ b/config/schema/knowledge.schema.yml @@ -260,3 +260,47 @@ block.settings.knowledge_block: field_name: type: string label: field_name + +knowledge.competency.settings: + type: config_object + label: 'Knowledge settings' + mapping: + roles: + type: sequence + orderby: weight + sequence: + type: mapping + mapping: + role: + type: string + label: 'Role' + weight: + type: integer + label: 'Weight' + action: + type: string + label: 'Action' + promote: + type: string + label: 'Promotion' + +field.field.*.*.*.third_party.knowledge: + type: mapping + label: 'Competency field settings' + mapping: + competency_role: + label: 'The role the competency field belongs to' + type: string + +field.formatter.settings.knowledge_competency: + type: mapping + mapping: + format: + type: string + label: 'Output format' + format_custom_false: + type: label + label: 'Custom output for FALSE' + format_custom_true: + type: label + label: 'Custom output for TRUE' diff --git a/css/competency-form.css b/css/competency-form.css index 5d2089d1e897f52dbed92130e2359e8724da1568..f83391032fb2ced3b836c215dbb4ded7dfec13db 100644 --- a/css/competency-form.css +++ b/css/competency-form.css @@ -1,3 +1,6 @@ -form[data-drupal-selector="knowledge-competency-form"] fieldset { - width: 95%; +div[data-drupal-selector="edit-roles-wrapper"] { + display: none; } +span.pull-right { + margin-left: 10px; +} \ No newline at end of file diff --git a/css/competency.admin.css b/css/competency.admin.css new file mode 100644 index 0000000000000000000000000000000000000000..55261b571dfcb407f26ac2c665377087a9e9c94c --- /dev/null +++ b/css/competency.admin.css @@ -0,0 +1,47 @@ +/* Block listing page */ +.role-title__action { + display: inline-block; + margin-left: 1em; /* LTR */ +} +[dir="rtl"] .role-title__action { + margin-right: 1em; + margin-left: 0; +} + +/* Block demo mode */ +.field-role { + margin-top: 4px; + margin-bottom: 4px; + padding: 3px; + color: #000; + background-color: #ff6; +} +a.field-demo-backlink, +a.field-demo-backlink:link, +a.field-demo-backlink:visited { + position: fixed; + z-index: 499; + left: 20px; /* LTR */ + padding: 5px 10px; + color: #000; + border-radius: 0 0 10px 10px; + background-color: #b4d7f0; + font-family: "Lucida Grande", Verdana, sans-serif; + font-size: small; + line-height: 20px; +} +a.field-demo-backlink:hover { + text-decoration: underline; +} + +/* Configure block form - Block description */ +.field-form .form-item-settings-admin-label label { + display: inline; +} +.field-form .form-item-settings-admin-label label::after { + content: ":"; +} +.field-disabled:not(:hover) { + opacity: 0.675; + background: #fcfcfa; +} diff --git a/js/competency-form.js b/js/competency-form.js new file mode 100644 index 0000000000000000000000000000000000000000..dc0eafc379474e450947ec6233ffb28377010564 --- /dev/null +++ b/js/competency-form.js @@ -0,0 +1,50 @@ +/** + * @file + * Defines JavaScript behaviors for the node module. + */ + +(function ($, Drupal) { + + /** + * Update the summary of a vertical tab. + */ + function updateSummary(element) { + const total = $(element).find('input[type="checkbox"]').length; + const correct = $(element).find('input[type="checkbox"]:checked').length; + var summary = Drupal.t('@correct of @total', {'@correct': correct, '@total': total}); + + if (correct > 0) { + const percent = Math.round((correct / total) * 100); + summary = Drupal.t('@correct of @total <span class="pull-right">@percent%</span>', {'@correct': correct, '@total': total, '@percent': percent}); + } + + + $(element).drupalSetSummary(summary); + } + + /** + * Behaviors for tabs in the node edit form. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches summary behavior for tabs in the node edit form. + */ + Drupal.behaviors.knowledgeCompetencySummaries = { + attach(context) { + + $(context).find('details.vertical-tabs__item').each(function () { + updateSummary(this); + }); + + once('knowledge-competency-summaries', 'details.vertical-tabs__item input[type="checkbox"]', context).forEach(function (element) { + $(element).on('change', function () { + // Your code to execute when the checkbox changes state + const parent =$(element).parents('details.vertical-tabs__item'); + updateSummary(parent); + }); + }); + + }, + }; +})(jQuery, Drupal); diff --git a/js/knowledge.competency.admin.js b/js/knowledge.competency.admin.js new file mode 100644 index 0000000000000000000000000000000000000000..ab521bf6d72962a7b5e762a8919de11a82fd877d --- /dev/null +++ b/js/knowledge.competency.admin.js @@ -0,0 +1,304 @@ +/** + * @file + * Competenc admin behaviors. + */ + +(function (window, $, Drupal, debounce, once) { + /** + * Filters the block list by a text input search string. + * + * The text input will have the selector `input.field-filter-text`. + * + * The target element to do searching in will be in the selector + * `input.field-filter-text[data-element]` + * + * The text source where the text should be found will have the selector + * `.field-filter-text-source` + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches the behavior for the block filtering. + */ + Drupal.behaviors.knowledgeCompetencyFilterByText = { + attach(context, settings) { + const $input = $(once('field-filter-text', 'input.field-filter-text')); + const $table = $($input.attr('data-element')); + let $filterRows; + + /** + * Filters the block list. + * + * @param {jQuery.Event} e + * The jQuery event for the keyup event that triggered the filter. + */ + function filterBlockList(e) { + const query = e.target.value.toLowerCase(); + + /** + * Shows or hides the block entry based on the query. + * + * @param {number} index + * The index in the loop, as provided by `jQuery.each` + * @param {HTMLElement} label + * The label of the block. + */ + function toggleBlockEntry(index, label) { + const $row = $(label).parent().parent(); + const textMatch = label.textContent.toLowerCase().includes(query); + $row.toggle(textMatch); + } + + // Filter if the length of the query is at least 2 characters. + if (query.length >= 2) { + $filterRows.each(toggleBlockEntry); + Drupal.announce( + Drupal.formatPlural( + $table.find('tr:visible').length - 1, + '1 block is available in the modified list.', + '@count blocks are available in the modified list.', + ), + ); + } else { + $filterRows.each(function (index) { + $(this).parent().parent().show(); + }); + } + } + + if ($table.length) { + $filterRows = $table.find('div.field-filter-text-source'); + $input.on('keyup', debounce(filterBlockList, 200)); + } + }, + }; + + /** + * Highlights the block that was just placed into the block listing. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches the behavior for the block placement highlighting. + */ + Drupal.behaviors.knowledgeCompetencyHighlightPlacement = { + attach(context, settings) { + // Ensure that the block we are attempting to scroll to actually exists. + if (settings.blockPlacement && $('.js-field-placed').length) { + once( + 'field-highlight', + '[data-drupal-selector="edit-fields"]', + context, + ).forEach((container) => { + const $container = $(container); + window.scrollTo({ + top: + $('.js-field-placed').offset().top - + $container.offset().top + + $container.scrollTop(), + behavior: 'smooth', + }); + }); + } + }, + }; + + /** + * Move a block in the blocks table between regions via select list. + * + * This behavior is dependent on the tableDrag behavior, since it uses the + * objects initialized in that behavior to update the row. + * + * @type {Drupal~behavior} + * + * @prop {Drupal~behaviorAttach} attach + * Attaches the tableDrag behavior for blocks in block administration. + */ + Drupal.behaviors.knowledgeCompetencyDrag = { + attach(context, settings) { + // tableDrag is required and we should be on the blocks admin page. + if ( + typeof Drupal.tableDrag === 'undefined' || + typeof Drupal.tableDrag.knowledge_competency === 'undefined' + ) { + return; + } + + /** + * Function to check empty regions and toggle classes based on this. + * + * @param {jQuery} table + * The jQuery object representing the table to inspect. + * @param {Drupal.tableDrag.row} rowObject + * Drupal table drag row dropped. + */ + function checkEmptyRegions(table, rowObject) { + 'debugger'; + table.find('tr.role-message').each(function () { + const $this = $(this); + // If the dragged row is in this region, but above the message row, + // swap it down one space. + if ($this.prev('tr').get(0) === rowObject.element) { + // Prevent a recursion problem when using the keyboard to move rows + // up. + if ( + rowObject.method !== 'keyboard' || + rowObject.direction === 'down' + ) { + rowObject.swap('after', this); + } + } + // This region has become empty. + if ( + $this.next('tr').length === 0 || + !$this.next('tr')[0].matches('.draggable') + ) { + $this.removeClass('role-populated').addClass('role-empty'); + } + // This region has become populated. + else if (this.matches('.role-empty')) { + $this.removeClass('role-empty').addClass('role-populated'); + } + }); + } + + /** + * Function to update the last placed row with the correct classes. + * + * @param {jQuery} table + * The jQuery object representing the table to inspect. + * @param {Drupal.tableDrag.row} rowObject + * Drupal table drag row dropped. + */ + function updateLastPlaced(table, rowObject) { + // Remove the color-success class from new block if applicable. + table.find('.color-success').removeClass('color-success'); + const $rowObject = $(rowObject); + if (!rowObject.element.matches('.drag-previous')) { + table.find('.drag-previous').removeClass('drag-previous'); + $rowObject.addClass('drag-previous'); + } + } + + /** + * Update block weights in the given region. + * + * @param {jQuery} table + * Table with draggable items. + * @param {string} region + * Machine name of region containing blocks to update. + */ + function updateBlockWeights(table, region) { + console.log(region); + // Calculate minimum weight. + let weight = -Math.round(table.find('.draggable').length / 2); + // Update the block weights. + table + .find(`.role-${region}-message`) + .nextUntil('.role-title') + .find('select.field-weight') + .each(function () { + // Increment the weight before assigning it to prevent using the + // absolute minimum available weight. This way we always have an + // unused upper and lower bound, which makes manually setting the + // weights easier for users who prefer to do it that way. + this.value = ++weight; + }); + } + + const table = $('#edit-fields'); + console.log(table); + // Get the blocks tableDrag object. + const tableDrag = Drupal.tableDrag.knowledge_competency; + // Add a handler for when a row is swapped, update empty regions. + tableDrag.row.prototype.onSwap = function (swappedRow) { + checkEmptyRegions(table, this); + updateLastPlaced(table, this); + }; + + // Add a handler so when a row is dropped, update fields dropped into + // new regions. + tableDrag.onDrop = function () { + const dragObject = this; + const $rowElement = $(dragObject.rowObject.element); + // Use "role-message" row instead of "region" row because + // "role-{region_name}-message" is less prone to regexp match errors. + const regionRow = $rowElement.prevAll('tr.role-message').get(0); + const regionName = regionRow.className.replace( + /([^ ]+[ ]+)*role-([^ ]+)-message([ ]+[^ ]+)*/, + '$2', + ); + const regionField = $rowElement.find('select.field-role-select'); + // Check whether the newly picked region is available for this block. + if (regionField.find(`option[value=${regionName}]`).length === 0) { + // If not, alert the user and keep the block in its old region + // setting. + window.alert(Drupal.t('The block cannot be placed in this region.')); + // Simulate that there was a selected element change, so the row is + // put back to from where the user tried to drag it. + regionField.trigger('change'); + } + + // Update region and weight fields if the region has been changed. + if (!regionField[0].matches(`.field-role-${regionName}`)) { + const weightField = $rowElement.find('select.field-weight'); + const oldRegionName = weightField[0].className.replace( + /([^ ]+[ ]+)*field-weight-([^ ]+)([ ]+[^ ]+)*/, + '$2', + ); + regionField + .removeClass(`field-role-${oldRegionName}`) + .addClass(`field-role-${regionName}`); + weightField + .removeClass(`field-weight-${oldRegionName}`) + .addClass(`field-weight-${regionName}`); + regionField[0].value = regionName; + } + + updateBlockWeights(table, regionName); + }; + + // Add the behavior to each region select list. + $(once('field-role-select', 'select.field-role-select', context)).on( + 'change', + function (event) { + // Make our new row and select field. + const row = $(this).closest('tr'); + const select = $(this); + // Find the correct region and insert the row as the last in the + // region. + tableDrag.rowObject = new tableDrag.row(row[0]); + const regionMessage = table.find( + `.role-${select[0].value}-message`, + ); + const regionItems = regionMessage.nextUntil( + '.role-message, .role-title', + ); + if (regionItems.length) { + regionItems.last().after(row); + } + // We found that regionMessage is the last row. + else { + regionMessage.after(row); + } + updateBlockWeights(table, select[0].value); + // Modify empty regions with added or removed fields. + checkEmptyRegions(table, tableDrag.rowObject); + // Update last placed block indication. + updateLastPlaced(table, tableDrag.rowObject); + // Show unsaved changes warning. + if (!tableDrag.changed) { + $(Drupal.theme('tableDragChangedWarning')) + .insertBefore(tableDrag.table) + .hide() + .fadeIn('slow'); + tableDrag.changed = true; + } + // Remove focus from selectbox. + select.trigger('blur'); + }, + ); + }, + }; + +})(window, jQuery, Drupal, Drupal.debounce, once); diff --git a/knowledge.info.yml b/knowledge.info.yml index 9033bf03f0b076952123ea02e855cba1104ea623..d4d2d82ac6a0273868b927f0c21ede44d675eddb 100644 --- a/knowledge.info.yml +++ b/knowledge.info.yml @@ -2,15 +2,14 @@ name: Knowledge type: module description: 'Allows users to link incidents to content.' package: Knowledge -core_version_requirement: ^9.0 || ^10.0 || ^11.0 +core_version_requirement: ^10.0 || ^11.0 +configure: knowledge.admin dependencies: - autocomplete_id:autocomplete_id - drupal:content_moderation - drupal:field - - drupal:field_layout - drupal:options - drupal:text - - field_group:field_group - search_api:search_api - token:token -configure: knowledge.admin + - knowledge:knowledge_field diff --git a/knowledge.install b/knowledge.install index ae74a2f8f13b8061b23c727bbfbe4ea577650417..d3c013fc6afc979fa8268221efb9c5c12a68aab5 100644 --- a/knowledge.install +++ b/knowledge.install @@ -6,6 +6,8 @@ */ use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\field\Entity\FieldStorageConfig; /** @@ -28,6 +30,40 @@ function knowledge_install() { // By default, maintain entity statistics for knowledge. // @see \Drupal\knowledge\KnowledgeStatisticsInterface \Drupal::state()->set('knowledge.maintain_entity_statistics', TRUE); + // Rebuild user entity form display for mobile number field. + $storage = \Drupal::entityTypeManager()->getStorage('entity_form_display'); + /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $user_form_display */ + $user_form_display = $storage->load('user.user.default'); + if (!$user_form_display) { + $user_form_display = $storage->create([ + 'targetEntityType' => 'user', + 'bundle' => 'user', + 'mode' => 'default', + 'status' => TRUE, + ]); + } + $user_form_display + ->setComponent('knowledge_coach', [ + 'type' => 'entity_reference_autocomplete', + 'weight' => 14, + 'settings' => [ + 'match_operator' => 'CONTAINS', + 'size' => '60', + 'placeholder' => '', + 'match_limit' => 10, + ], + ]) + ->setComponent('knowledge_leader', [ + 'type' => 'entity_reference_autocomplete', + 'weight' => 14, + 'settings' => [ + 'match_operator' => 'CONTAINS', + 'size' => '60', + 'placeholder' => '', + 'match_limit' => 10, + ], + ]) + ->save(); } /** @@ -232,3 +268,420 @@ function knowledge_schema() { return $schema; } + +/** + * Competency refactor, removes 'Field Group' dependency. + */ +function knowledge_update_8103(&$sandbox) { + $fields = [ + 'field_audience' => 'knowledge_publisher', + 'field_business' => 'knowledge_contributor', + 'field_capture_context' => 'knowledge_publisher', + 'field_capture_in_the_moment' => 'knowledge_publisher', + 'field_collaborate' => 'knowledge_publisher', + 'field_complete_thoughts' => 'knowledge_contributor', + 'field_confidence' => 'knowledge_publisher', + 'field_content_standard' => 'knowledge_publisher', + 'field_documents_request' => 'knowledge_contributor', + 'field_fix_it' => 'knowledge_contributor', + 'field_flag_it' => 'knowledge_candidate', + 'field_improve' => 'knowledge_publisher', + 'field_includes_context' => 'knowledge_contributor', + 'field_iterative_search' => 'knowledge_publisher', + 'field_kcs_article_elements' => 'knowledge_contributor', + 'field_link_it' => 'knowledge_candidate', + 'field_one' => 'knowledge_contributor', + 'field_process_adherence' => 'knowledge_publisher', + 'field_relevant' => 'knowledge_publisher', + 'field_reuse' => 'knowledge_contributor', + 'field_search_it' => 'knowledge_candidate', + 'field_solve_loop' => 'knowledge_contributor', + 'field_structure' => 'knowledge_contributor', + 'field_sufficient_to_solve' => 'knowledge_publisher', + 'field_update_or_create' => 'knowledge_contributor', + ]; + + if (!isset($sandbox['progress'])) { + // This must be the first run. Initialize the sandbox. + $sandbox['progress'] = 0; + $sandbox['max'] = 6; + } + + // Create knowledge.competency.settings. + if ($sandbox['progress'] == 1) { + $settings = \Drupal::service('config.factory') + ->getEditable('knowledge.competency.settings'); + $roles = [ + [ + 'role' => 'knowledge_candidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 2, + 'action' => 'auto', + 'promote' => 'self', + ], + ]; + $settings->set('roles', $roles); + $settings->save(); + + // Field definition settings. + $fields_definitions = \Drupal::service('entity_field.manager') + ->getFieldDefinitions('knowledge_competency', 'knowledge_competency'); + + foreach ($fields as $field_id => $role) { + $fields_definitions[$field_id]->setThirdPartySetting('knowledge', 'competency_role', $role); + $fields_definitions[$field_id]->save(); + } + + } + + // Install new dependency. + if ($sandbox['progress'] == 2) { + // Install the. + \Drupal::service('module_installer')->install(['knowledge_field'], TRUE); + // Clear Cache. + drupal_flush_all_caches(); + } + + // Adds new fields. + if ($sandbox['progress'] == 3) { + $roles_field_definition = BaseFieldDefinition::create('knowledge_competency_role') + ->setLabel(t('Roles')) + ->setDescription(t('The roles of the user.')) + ->setRevisionable(TRUE) + ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) + ->setDisplayOptions('view', [ + 'label' => 'hidden', + 'type' => 'knowledge_competency_role', + 'weight' => 0, + ]) + ->setDisplayOptions('form', [ + 'type' => 'knowledge_competency_role', + 'weight' => 5, + ]) + ->setDisplayConfigurable('view', TRUE) + ->setDisplayConfigurable('form', TRUE); + + \Drupal::entityDefinitionUpdateManager() + ->installFieldStorageDefinition('roles', 'knowledge_competency', 'knowledge_competency', $roles_field_definition); + + $completed = BaseFieldDefinition::create('timestamp') + ->setLabel(t('Completed')) + ->setDescription(t('The time that correct = total.')) + ->setRevisionable(FALSE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', TRUE); + + \Drupal::entityDefinitionUpdateManager() + ->installFieldStorageDefinition('completed', 'knowledge_competency', 'knowledge_competency', $completed); + + } + + // Adds 'roles' data to revisions. + if ($sandbox['progress'] == 4) { + + $database = \Drupal::database(); + if (!isset($sandbox['competency_ids'])) { + $database->update('knowledge_competency') + ->isNull('completed') + ->isNotNull('publisher_proposed') + ->expression('completed', 'publisher_proposed') + ->execute(); + + $sandbox['competency_ids'] = \Drupal::entityQuery('knowledge_competency') + ->accessCheck(FALSE) + ->execute(); + + $sandbox['competency_total'] = count($sandbox['competency_ids']); + } + else { + + $competency_id = array_pop($sandbox['competency_ids']); + $query = $database->select('knowledge_competency_revision', 'kcr'); + $query->addField('kcr', 'vid'); + $query->condition('id', $competency_id); + $revision_ids = $query->execute()->fetchAll(); + + $competency_storage = \Drupal::entityTypeManager()->getStorage('knowledge_competency'); + $entity = $competency_storage->load($competency_id); + + $score = [ + 'knowledge_candidate' => [ + 'correct' => 0, + 'total' => 0, + ], + 'knowledge_contributor' => [ + 'correct' => 0, + 'total' => 0, + ], + 'knowledge_publisher' => [ + 'correct' => 0, + 'total' => 0, + ], + ]; + + foreach ($fields as $field => $role) { + $score[$role]['total'] += 1; + if ($entity->get($field)->value) { + $score[$role]['correct'] += 1; + } + $score[$role]['completed'] = ($score[$role]['correct'] == $score[$role]['total']) + ? $entity->get('revision_timestamp')->value + : NULL; + } + + $database->insert('knowledge_competency__roles') + ->fields([ + 'bundle', + 'deleted', + 'entity_id', + 'langcode', + 'delta', + 'roles_role', + 'roles_correct', + 'roles_total', + 'roles_proposer', + 'roles_approver', + 'roles_proposed', + 'roles_approved', + 'revision_id', + ]) + ->values([ + 'bundle' => 'knowledge_competency', + 'deleted' => 0, + 'entity_id' => $competency_id, + 'langcode' => 'en', + 'delta' => 0, + 'roles_role' => 'knowledge_candidate', + 'roles_correct' => $score['knowledge_candidate']['correct'], + 'roles_total' => $score['knowledge_candidate']['total'], + 'roles_proposer' => NULL, + 'roles_approver' => NULL, + 'roles_proposed' => $score['knowledge_candidate']['completed'], + 'roles_approved' => $score['knowledge_candidate']['completed'], + 'revision_id' => $entity->getRevisionId(), + ]) + ->values([ + 'bundle' => 'knowledge_competency', + 'deleted' => 0, + 'entity_id' => $competency_id, + 'langcode' => 'en', + 'delta' => 1, + 'roles_role' => 'knowledge_contributor', + 'roles_correct' => $score['knowledge_contributor']['correct'], + 'roles_total' => $score['knowledge_contributor']['total'], + 'roles_proposer' => NULL, + 'roles_approver' => NULL, + 'roles_proposed' => $score['knowledge_contributor']['completed'], + 'roles_approved' => $score['knowledge_contributor']['completed'], + 'revision_id' => $entity->getRevisionId(), + ]) + ->values([ + 'bundle' => 'knowledge_competency', + 'deleted' => 0, + 'entity_id' => $competency_id, + 'langcode' => 'en', + 'delta' => 2, + 'roles_role' => 'knowledge_publisher', + 'roles_correct' => $score['knowledge_publisher']['correct'], + 'roles_total' => $score['knowledge_publisher']['total'], + 'roles_proposer' => $entity->get('publisher_coach')?->target_id, + 'roles_approver' => $entity->get('publisher_leader')?->target_id, + 'roles_proposed' => $entity->get('publisher_proposed')->value, + 'roles_approved' => $entity->get('publisher_approved')->value, + 'revision_id' => $entity->getRevisionId(), + ])->execute(); + + foreach ($revision_ids as $id => $vid) { + $revision = $competency_storage->loadRevision($vid->vid); + $score = [ + 'knowledge_candidate' => [ + 'correct' => 0, + 'total' => 0, + ], + 'knowledge_contributor' => [ + 'correct' => 0, + 'total' => 0, + ], + 'knowledge_publisher' => [ + 'correct' => 0, + 'total' => 0, + ], + ]; + + foreach ($fields as $field => $role) { + $score[$role]['total'] += 1; + if ($revision->get($field)->value) { + $score[$role]['correct'] += 1; + } + $score[$role]['completed'] = ($score[$role]['correct'] == $score[$role]['total']) + ? $revision->get('revision_timestamp')->value + : NULL; + } + + $database->insert('knowledge_competency_revision__roles') + ->fields([ + 'bundle', + 'deleted', + 'entity_id', + 'langcode', + 'delta', + 'roles_role', + 'roles_correct', + 'roles_total', + 'roles_proposer', + 'roles_approver', + 'roles_proposed', + 'roles_approved', + 'revision_id', + ]) + ->values([ + 'bundle' => 'knowledge_competency', + 'deleted' => 0, + 'entity_id' => $competency_id, + 'langcode' => 'en', + 'delta' => 0, + 'roles_role' => 'knowledge_candidate', + 'roles_correct' => $score['knowledge_candidate']['correct'], + 'roles_total' => $score['knowledge_candidate']['total'], + 'roles_proposer' => NULL, + 'roles_approver' => NULL, + 'roles_proposed' => $score['knowledge_candidate']['completed'], + 'roles_approved' => $score['knowledge_candidate']['completed'], + 'revision_id' => $vid->vid, + ]) + ->values([ + 'bundle' => 'knowledge_competency', + 'deleted' => 0, + 'entity_id' => $competency_id, + 'langcode' => 'en', + 'delta' => 1, + 'roles_role' => 'knowledge_contributor', + 'roles_correct' => $score['knowledge_contributor']['correct'], + 'roles_total' => $score['knowledge_contributor']['total'], + 'roles_proposer' => NULL, + 'roles_approver' => NULL, + 'roles_proposed' => $score['knowledge_contributor']['completed'], + 'roles_approved' => $score['knowledge_contributor']['completed'], + 'revision_id' => $vid->vid, + ]) + ->values([ + 'bundle' => 'knowledge_competency', + 'deleted' => 0, + 'entity_id' => $competency_id, + 'langcode' => 'en', + 'delta' => 2, + 'roles_role' => 'knowledge_publisher', + 'roles_correct' => $score['knowledge_publisher']['correct'], + 'roles_total' => $score['knowledge_publisher']['total'], + 'roles_proposer' => $entity->get('publisher_coach')?->target_id, + 'roles_approver' => $entity->get('publisher_leader')?->target_id, + 'roles_proposed' => $entity->get('publisher_proposed')->value, + 'roles_approved' => $entity->get('publisher_approved')->value, + 'revision_id' => $vid->vid, + ])->execute(); + + } + } + $remaining_competency = count($sandbox['competency_ids']); + if ($remaining_competency) { + $competency_total = $sandbox['competency_total']; + $sandbox['#finished'] = ($competency_total - $remaining_competency) / $competency_total; + return; + } + + } + + $sandbox['progress'] += 1; + $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max']; + + // Updates existing field definitions. + if ($sandbox['progress'] == 6) { + $sandbox = []; + + \Drupal::entityTypeManager()->clearCachedDefinitions(); + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); + $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository'); + + $entity_type = $definition_update_manager->getEntityType('knowledge_competency'); + $entity_type->set('class', 'Drupal\knowledge\Entity\Competency'); + $entity_type->set('admin_permission', 'administer knowledge_competency'); + + $handlers = $entity_type->get('handlers'); + $handlers['storage'] = 'Drupal\knowledge\CompetencyStorage'; + $handlers['list_builder'] = 'Drupal\knowledge\CompetencyListBuilder'; + $handlers['views_data'] = 'Drupal\knowledge\CompetencyViewsData'; + $handlers['form'] = [ + 'default' => 'Drupal\knowledge\Form\CompetencyForm', + 'add' => 'Drupal\knowledge\Form\CompetencyForm', + 'edit' => 'Drupal\knowledge\Form\CompetencyForm', + 'delete' => 'Drupal\knowledge\Form\CompetencyDeleteForm', + 'approve' => 'Drupal\knowledge\Form\CompetencyApproveForm', + ]; + $handlers['route_provider']['html'] = 'Drupal\knowledge\CompetencyHtmlRouteProvider'; + $handlers['access'] = 'Drupal\knowledge\CompetencyAccessControlHandler'; + $entity_type->set('handlers', $handlers); + + $field_storage_definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions('knowledge_competency'); + + $field_storage_definitions['user_id']->setDisplayConfigurable('form', FALSE); + + $field_storage_definitions['contributor_coach']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['contributor_coach']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['contributor_leader']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['contributor_leader']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['publisher_coach']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['publisher_coach']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['publisher_leader']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['publisher_leader']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['contributor_proposed']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['contributor_proposed']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['contributor_approved']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['contributor_approved']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['publisher_proposed']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['publisher_proposed']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['publisher_approved']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['publisher_approved']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['candidate_correct']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['candidate_correct']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['candidate_total']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['candidate_total']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['contributor_correct']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['contributor_correct']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['contributor_total']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['contributor_total']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['publisher_correct']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['publisher_correct']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['publisher_total']->setDisplayConfigurable('form', FALSE); + $field_storage_definitions['publisher_total']->setDisplayConfigurable('view', FALSE); + + $field_storage_definitions['correct']->setDisplayConfigurable('view', TRUE); + $field_storage_definitions['total']->setDisplayConfigurable('view', TRUE); + + $definition_update_manager->updateFieldableEntityType($entity_type, $field_storage_definitions, $sandbox); + } + +} diff --git a/knowledge.libraries.yml b/knowledge.libraries.yml index cc663a7639f68324d1fc5c8218724c8766e6f6ce..662dc4aba79151952f9ddce713978b2093de1950 100644 --- a/knowledge.libraries.yml +++ b/knowledge.libraries.yml @@ -88,6 +88,12 @@ competency_form: css: layout: css/competency-form.css: {} + js: + js/competency-form.js: {} + dependencies: + - core/drupal.entity-form + - core/jquery + - core/once competency_report: version: VERSION @@ -100,3 +106,19 @@ competency_report: - core/jquery - core/once - moderation_dashboard/chart.js.external + +competency.admin: + version: VERSION + js: + js/knowledge.competency.admin.js: {} + css: + theme: + css/competency.admin.css: {} + dependencies: + - core/jquery + - core/drupal + - core/drupal.announce + - core/drupal.debounce + - core/drupal.dialog.ajax + - core/drupal.tabledrag + - core/once \ No newline at end of file diff --git a/knowledge.links.task.yml b/knowledge.links.task.yml index 3c2b356a198de7cb9d5e42f09e0970f25551312d..9ba6b03dd885e9ce139ea13b71797f276b4e0680 100644 --- a/knowledge.links.task.yml +++ b/knowledge.links.task.yml @@ -115,6 +115,17 @@ knowledge_competency.settings_tab: title: 'Settings' base_route: knowledge_competency.settings +knowledge_competency.settings: + title: 'Competencies' + route_name: knowledge_competency.settings + parent_id: knowledge_competency.settings_tab + weight: -10 + +knowledge_competency.settings.role: + title: 'Roles' + route_name: knowledge_competency.settings.role + parent_id: knowledge_competency.settings_tab + entity.knowledge_competency.canonical: route_name: entity.knowledge_competency.canonical base_route: entity.knowledge_competency.canonical @@ -141,6 +152,12 @@ entity.user.knowledge_competency_tab: title: 'Competency' base_route: entity.user.canonical +entity.knowledge_competency.collection: + title: 'Competency' + route_name: entity.knowledge_competency.collection + parent_id: knowledge.admin + weight: 20 + entity.knowledge_wave.view: title: 'View' route_name: entity.knowledge_wave.canonical diff --git a/knowledge.module b/knowledge.module index 3a84a9c9f3444468912f58a0bacdee6c531c1261..245901f303581448d3e7d135ad5a61b81f2082dc 100644 --- a/knowledge.module +++ b/knowledge.module @@ -927,7 +927,7 @@ function knowledge_library_info_alter(&$libraries, $extension) { /** * Allowed values for the audience field. */ -function knowledge_audience_allowed_values(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL) { +function knowledge_audience_allowed_values(FieldStorageDefinitionInterface $definition, ?FieldableEntityInterface $entity = NULL) { $has_permission = \Drupal::currentUser() ->hasPermission('create knowledge audience external'); @@ -982,7 +982,7 @@ function knowledge_node_access(NodeInterface $node, $op, AccountInterface $accou } if ($node->hasField('knowledge_governance') && $node->get('knowledge_governance')->value) { - if (!empty(array_intersect($account->getRoles(), $user_roles))) { + if (!empty(array_intersect($account->getRoles(TRUE), $user_roles))) { return AccessResult::allowed(); } elseif (in_array($account->id(), $users)) { @@ -1046,10 +1046,13 @@ function knowledge_node_presave(EntityInterface $entity) { * Implements hook_ENTITY_TYPE_ID_presave(). */ function knowledge_user_presave(EntityInterface $entity) { + /** @var \Drupal\user\UserInterface $user */ + $user = $entity; + + \Drupal::service('knowledge.competency')->doRoleRemoval($user); try { - /** @var \Drupal\user\UserInterface $user */ - $user = $entity; + $leadership_changed = FALSE; if ($user->isNew()) { $leadership_changed = TRUE; @@ -1064,7 +1067,7 @@ function knowledge_user_presave(EntityInterface $entity) { if ($user->get('knowledge_leader')->target_id) { $leader = $user->get('knowledge_leader')->entity; - $roles = $leader->getRoles(); + $roles = $leader->getRoles(TRUE); if (!in_array('knowledge_leader', $roles)) { $leader_svc->addKnowledgeLeader($leader); } @@ -1108,7 +1111,7 @@ function knowledge_user_delete(EntityInterface $entity) { /** * Implements hook_entity_field_access(). */ -function knowledge_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) { +function knowledge_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) { $permission = NULL; $field_name = $field_definition->getName(); diff --git a/knowledge.permissions.yml b/knowledge.permissions.yml index e2653bd316ae4272c761812959c4e7b1f4746c85..46a58cf5855720ab9617adfb4c92178768d8c72d 100644 --- a/knowledge.permissions.yml +++ b/knowledge.permissions.yml @@ -1,16 +1,22 @@ administer knowledge: title: 'Administer knowledge and knowledge settings' + administer knowledge types: title: 'Administer knowledge types and settings' restrict access: true + access knowledge: title: 'View knowledge' + post knowledge: title: 'Post knowledge' + skip knowledge approval: title: 'Skip knowledge approval' + edit own knowledge: title: 'Edit own knowledge' + edit own learners field: title: 'Edit own learners field' @@ -68,36 +74,58 @@ delete all quality revisions: access knowledge reports: title: 'Access knowledge reports' description: 'Access knowledge reports' -add competency entities: - title: 'Create new Competency entities' -administer competency entities: - title: 'Administer Competency entities' +add knowledge_competency: + title: 'Create new Competency' + +administer knowledge_competency: + title: 'Administer Competency' description: 'Allow to access the administration form to configure Competency entities.' restrict access: true -delete competency entities: - title: 'Delete Competency entities' +edit other knowledge_competency: + title: "Edit Other's Competency" + description: 'Edit other users Competency. Can not edit own Competency.' + +edit own knowledge_competency: + title: 'Edit own Competency' + description: 'Competency can change roles. A users should not have control over their comptency.' + restrict access: true + +edit learner knowledge_competency: + title: 'Edit Learners Competency' + description: 'If you are their coach' + +view own knowledge_competency: + title: 'View Own Competency' + +view learner knowledge_competency: + title: 'View Learner Competency' + description: 'If you are their coach' + +view follower knowledge_competency: + title: 'View Follower Competency' + description: 'If you are their leader' -edit competency entities: - title: 'Edit Competency entities' +view any knowledge_competency: + title: 'View Any Competency' -view published competency entities: - title: 'View published Competency entities' +view published knowledge_competency: + title: 'View published Competency' -view unpublished competency entities: - title: 'View unpublished Competency entities' +view unpublished knowledge_competency: + title: 'View unpublished Competency' -view all competency revisions: +view all knowledge_competency revisions: title: 'View all Competency revisions' -revert all competency revisions: +revert all knowledge_competency revisions: title: 'Revert all Competency revisions' - description: 'Role requires permission <em>view Competency revisions</em> and <em>edit rights</em> for competency entities in question or <em>administer competency entities</em>.' + description: 'Role requires permission <em>view Competency revisions</em> and <em>edit rights</em> for competency entities in question or <em>administer knowledge_competency</em>.' -delete all competency revisions: +delete all knowledge_competency revisions: title: 'Delete all revisions' - description: 'Role requires permission to <em>view Competency revisions</em> and <em>delete rights</em> for competency entities in question or <em>administer competency entities</em>.' + description: 'Role requires permission to <em>view Competency revisions</em> and <em>delete rights</em> for competency entities in question or <em>administer knowledge_competency</em>.' # permission_callbacks: # - \Drupal\knowledge\KnowledgePermissions::permissions diff --git a/knowledge.routing.yml b/knowledge.routing.yml index 6212e55eec928d73e84be59e4455ca86ddcb886e..09519234fcc1c4e68788efa70e5bee5ed6b5c378 100644 --- a/knowledge.routing.yml +++ b/knowledge.routing.yml @@ -185,28 +185,32 @@ knowledge.admin_reports: entity.user.knowledge_competency: path: '/user/{user}/competency' defaults: - _controller: '\Drupal\knowledge\Controller\KnowledgeCompetencyController::userCompetency' + _controller: '\Drupal\knowledge\Controller\CompetencyController::userCompetency' requirements: - _permission: 'view published competency entities' - user: \d+ + _custom_access: '\Drupal\knowledge\Controller\CompetencyController::accessUserCompetency' options: _admin_route: TRUE + parameters: + user: + type: entity:user entity.user.knowledge_competency.approval_form: path: '/user/{user}/competency/approve' defaults: - _form: '\Drupal\knowledge\Form\KnowledgeCompetencyApproveForm' + _form: '\Drupal\knowledge\Form\CompetencyApproveForm' _title: 'Approval' requirements: - _custom_access: '\Drupal\knowledge\Controller\KnowledgeCompetencyController::accessCompetencyApproval' - user: \d+ + _custom_access: '\Drupal\knowledge\Controller\CompetencyController::accessCompetencyApproval' options: _admin_route: TRUE + parameters: + user: + type: entity:user knowledge.report.competency: path: '/admin/reports/knowledge/competency' defaults: - _controller: '\Drupal\knowledge\Controller\KnowledgeCompetencyController::competencySummaryReport' + _controller: '\Drupal\knowledge\Controller\CompetencyController::competencySummaryReport' _title: 'Knowledge' requirements: _permission: 'access knowledge reports' diff --git a/knowledge.services.yml b/knowledge.services.yml index d007a511f6f387c5457dfdd17c4dab57b69c6e47..c935ed1fc1ed9a6918b41fdad1a6fce480dfed5b 100644 --- a/knowledge.services.yml +++ b/knowledge.services.yml @@ -73,3 +73,11 @@ services: class: Drupal\knowledge\Service\KnowledgeLinkRelationship arguments: - '@entity_type.manager' + + knowledge.competency: + class: '\Drupal\knowledge\Service\CompetencyService' + arguments: + - '@config.factory' + - '@entity_type.manager' + - '@string_translation' + - '@messenger' diff --git a/modules/knowledge_field/config/schema/knowledge_field.schema.yml b/modules/knowledge_field/config/schema/knowledge_field.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..e63fafcb4715ea2b46a66af57392355cb35a7279 --- /dev/null +++ b/modules/knowledge_field/config/schema/knowledge_field.schema.yml @@ -0,0 +1,42 @@ +field.value.knowledge_competency_role: + type: mapping + label: Default value + mapping: + role: + type: label + label: Role + correct: + type: integer + label: Correct + total: + type: integer + label: Total + proposer: + type: integer + label: Proposer + proposed: + type: integer + label: Proposed + approver: + type: integer + label: Approver + approved: + type: integer + label: Approved + + +field.formatter.settings.knowledge_competency_role: + type: mapping + label: Competency Role formatter settings + mapping: + foo: + type: string + label: Foo + +field.widget.settings.knowledge_competency_role: + type: mapping + label: Competency Role widget settings + mapping: + foo: + type: string + label: Foo diff --git a/modules/knowledge_field/knowledge_field.info.yml b/modules/knowledge_field/knowledge_field.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..5eff247116db312dc95508a9786f1cab5bd1ae1a --- /dev/null +++ b/modules/knowledge_field/knowledge_field.info.yml @@ -0,0 +1,5 @@ +name: 'Knowledge fields' +type: module +description: 'Custom fields used by knowledge entities.' +package: Knowledge +core_version_requirement: ^10 diff --git a/modules/knowledge_field/knowledge_field.module b/modules/knowledge_field/knowledge_field.module new file mode 100644 index 0000000000000000000000000000000000000000..dc7c6cf909e43e2b81e723f11ba152e9ad8d06b2 --- /dev/null +++ b/modules/knowledge_field/knowledge_field.module @@ -0,0 +1,8 @@ +<?php + +/** + * @file + * Contains . + */ + +declare(strict_types=1); diff --git a/modules/knowledge_field/src/Helper/CompetencyField.php b/modules/knowledge_field/src/Helper/CompetencyField.php new file mode 100644 index 0000000000000000000000000000000000000000..311b544e72e5e27e5a99a2a2efe85321fba4980b --- /dev/null +++ b/modules/knowledge_field/src/Helper/CompetencyField.php @@ -0,0 +1,38 @@ +<?php + +namespace Drupal\knowledge_field\Helper; + +/** + * Helper class for the knowledge competency entity. + */ +class CompetencyField { + + /** + * Get the field definitions for the knowledge competency entity. + * + * @param \Drupal\Core\Field\FieldDefinitionInterface[] $field_definitions + * The field definitions. + * + * @return array + * The field definitions for the knowledge competency entity. + */ + public static function roleFields($field_definitions) { + $fields = []; + foreach ($field_definitions as $field_name => $field_definition) { + if ($field_definition->getType() != 'boolean') { + continue; + } + if (get_class($field_definition) != 'Drupal\field\Entity\FieldConfig') { + continue; + } + $role = $field_definition->getThirdPartySetting('knowledge', 'competency_role', '_none'); + if ($role == '_none') { + continue; + } + $fields[$role][] = $field_name; + } + + return $fields; + } + +} diff --git a/modules/knowledge_field/src/Plugin/Field/FieldFormatter/KnowledgeCompetencyRoleFormatter.php b/modules/knowledge_field/src/Plugin/Field/FieldFormatter/KnowledgeCompetencyRoleFormatter.php new file mode 100644 index 0000000000000000000000000000000000000000..dd8f9d5336551ceaf0c089b9fce7dea25ebe4a62 --- /dev/null +++ b/modules/knowledge_field/src/Plugin/Field/FieldFormatter/KnowledgeCompetencyRoleFormatter.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\knowledge_field\Plugin\Field\FieldFormatter; + +use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Field\FormatterBase; +use Drupal\Core\Form\FormStateInterface; + +/** + * Plugin implementation of the 'Competency Role' formatter. + * + * @FieldFormatter( + * id = "knowledge_competency_role", + * label = @Translation("Competency Role"), + * field_types = {"knowledge_competency_role"}, + * ) + */ +final class KnowledgeCompetencyRoleFormatter extends FormatterBase { + + /** + * {@inheritdoc} + */ + public static function defaultSettings(): array { + $setting = ['foo' => 'bar']; + return $setting + parent::defaultSettings(); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state): array { + $elements['foo'] = [ + '#type' => 'textfield', + '#title' => $this->t('Foo'), + '#default_value' => $this->getSetting('foo'), + ]; + return $elements; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary(): array { + return [ + $this->t('Foo: @foo', ['@foo' => $this->getSetting('foo')]), + ]; + } + + /** + * {@inheritdoc} + */ + public function viewElements(FieldItemListInterface $items, $langcode): array { + $element = []; + foreach ($items as $delta => $item) { + $element[$delta] = [ + '#markup' => $item->value, + ]; + } + return $element; + } + +} diff --git a/modules/knowledge_field/src/Plugin/Field/FieldType/KnowledgeCompetencyRoleItem.php b/modules/knowledge_field/src/Plugin/Field/FieldType/KnowledgeCompetencyRoleItem.php new file mode 100644 index 0000000000000000000000000000000000000000..760d1f8f414805bf23bfc4a03e4ffba91d9faa37 --- /dev/null +++ b/modules/knowledge_field/src/Plugin/Field/FieldType/KnowledgeCompetencyRoleItem.php @@ -0,0 +1,227 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\knowledge_field\Plugin\Field\FieldType; + +use Drupal\Component\Utility\Random; +use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\Field\FieldItemBase; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\Core\TypedData\DataDefinition; +use Drupal\knowledge_field\Helper\CompetencyField; + +/** + * Defines the 'knowledge_competency_role' field type. + * + * @FieldType( + * id = "knowledge_competency_role", + * label = @Translation("Competency Roles"), + * description = @Translation("Tracks role progress."), + * default_widget = "knowledge_competency_role", + * default_formatter = "knowledge_competency_role", + * no_ui = TRUE, + * ) + */ +final class KnowledgeCompetencyRoleItem extends FieldItemBase { + + /** + * {@inheritdoc} + */ + public static function mainPropertyName() { + return 'role'; + } + + /** + * {@inheritdoc} + */ + public function isEmpty(): bool { + return match ($this->get('role')->getValue()) { + NULL, '' => TRUE, + default => FALSE, + }; + } + + /** + * {@inheritdoc} + */ + public static function defaultStorageSettings() { + return [ + 'target_type' => 'user', + 'title' => '', + ] + parent::defaultStorageSettings(); + } + + /** + * {@inheritdoc} + */ + public static function defaultFieldSettings() { + return [ + 'handler' => 'default', + 'target_type' => 'user', + 'handler_settings' => [], + ] + parent::defaultFieldSettings(); + } + + /** + * {@inheritdoc} + */ + public function getTargetDefinition() { + return $this->targetDefinition; + } + + /** + * {@inheritdoc} + */ + public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition): array { + + // @DCG + // See /core/lib/Drupal/Core/TypedData/Plugin/DataType directory for + // available data types. + $properties['role'] = DataDefinition::create('string') + ->setLabel(t('Role')) + ->setRequired(TRUE); + + $properties['correct'] = DataDefinition::create('integer') + ->setLabel(t('Correct')) + ->setRequired(TRUE); + + $properties['total'] = DataDefinition::create('integer') + ->setLabel(t('Total')) + ->setRequired(TRUE); + + $properties['proposer'] = DataDefinition::create('entity_reference') + ->setLabel(t('Proposer')) + ->setSetting('target_type', 'user') + ->setRequired(FALSE); + + $properties['approver'] = DataDefinition::create('entity_reference') + ->setLabel(t('Approver')) + ->setSetting('target_type', 'user') + ->setRequired(FALSE); + + $properties['proposed'] = DataDefinition::create('integer') + ->setLabel(t('Proposed')) + ->setRequired(FALSE); + + $properties['approved'] = DataDefinition::create('integer') + ->setLabel(t('Approved')) + ->setRequired(FALSE); + + return $properties; + } + + /** + * {@inheritdoc} + */ + public function getConstraints(): array { + $constraints = parent::getConstraints(); + + $constraint_manager = $this->getTypedDataManager()->getValidationConstraintManager(); + + // @DCG Suppose our value must not be longer than 10 characters. + // $options['value']['Length']['max'] = 10; + // @DCG + // See /core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint + // directory for available constraints. + // $constraints[] = $constraint_manager->create('ComplexData', $options); + return $constraints; + } + + /** + * {@inheritdoc} + */ + public static function schema(FieldStorageDefinitionInterface $field_definition): array { + + $columns = [ + 'role' => [ + 'type' => 'varchar', + 'not null' => FALSE, + 'description' => 'Column description.', + 'length' => 255, + ], + 'correct' => [ + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'Column description.', + ], + 'total' => [ + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'Column description.', + ], + 'proposer' => [ + 'type' => 'int', + 'not null' => FALSE, + 'unsigned' => TRUE, + 'description' => 'The user who proposed the advancement.', + ], + 'approver' => [ + 'type' => 'int', + 'not null' => FALSE, + 'unsigned' => TRUE, + 'description' => 'The users that appoved the advacement.', + ], + 'proposed' => [ + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'When advancement is proposed.', + ], + 'approved' => [ + 'type' => 'int', + 'not null' => FALSE, + 'description' => 'When advancement is appoved.', + ], + + ]; + + $schema = [ + 'columns' => $columns, + // @todo Add indexes here if necessary. + ]; + + return $schema; + } + + /** + * {@inheritdoc} + */ + public function preSave() { + $entity = $this->getEntity(); + $definitions = $entity->getFieldDefinitions(); + $roles = CompetencyField::roleFields($definitions); + $role = $this->values['role']; + $fields = $roles[$role] ?? []; + $this->total = 0; + $this->correct = 0; + foreach ($fields as $field) { + $value = $entity->get($field)->value; + if ($value) { + $this->correct += 1; + } + $this->total += 1; + } + + parent::preSave(); + } + + /** + * {@inheritdoc} + */ + public static function generateSampleValue(FieldDefinitionInterface $field_definition): array { + $random = new Random(); + $values['role'] = $random->word(mt_rand(1, 50)); + return $values; + } + + /** + * Is the field item pending approval. + * + * @return bool + * TRUE if the field item is pending approval. + */ + public function isPending(): bool { + return $this->proposed !== NULL && $this->approved === NULL; + } + +} diff --git a/modules/knowledge_field/src/Plugin/Field/FieldWidget/KnowledgeCompetencyRoleWidget.php b/modules/knowledge_field/src/Plugin/Field/FieldWidget/KnowledgeCompetencyRoleWidget.php new file mode 100644 index 0000000000000000000000000000000000000000..15f024ff2bf62606833fad3f70bd088afd7406cf --- /dev/null +++ b/modules/knowledge_field/src/Plugin/Field/FieldWidget/KnowledgeCompetencyRoleWidget.php @@ -0,0 +1,286 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\knowledge_field\Plugin\Field\FieldWidget; + +use Drupal\Core\Config\ImmutableConfig; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Field\FieldDefinitionInterface; +use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Field\WidgetBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\knowledge\KnowledgeCompetencyInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * Defines the 'knowledge_competency_role' field widget. + * + * @FieldWidget( + * id = "knowledge_competency_role", + * label = @Translation("Competency Role"), + * field_types = {"knowledge_competency_role"}, + * ) + */ +final class KnowledgeCompetencyRoleWidget extends WidgetBase { + + /** + * The field definitions. + * + * @var array + */ + protected $fieldDefinitions; + + /** + * The competency settings. + * + * @var \Drupal\Core\Config\ImmutableConfig + */ + protected $competencySettings; + + /** + * The user storage. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $userStorage; + + /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + + /** + * Constructs a Competency Role widget. + * + * @param string $plugin_id + * The plugin_id for the widget. + * @param mixed $plugin_definition + * The plugin implementation definition. + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The definition of the field to which the widget is associated. + * @param array $settings + * The widget settings. + * @param array $third_party_settings + * Any third party settings. + * @param array $fields_definitions + * The field definitions. + * @param \Drupal\Core\Config\ImmutableConfig $competency_settings + * The settings. + * @param \Drupal\Core\Entity\EntityStorageInterface $user_storage + * The user storage. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * The event dispatcher. + */ + public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, array $fields_definitions, ImmutableConfig $competency_settings, EntityStorageInterface $user_storage, EventDispatcherInterface $event_dispatcher) { + parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings); + $this->fieldDefinitions = $fields_definitions; + $this->competencySettings = $competency_settings; + $this->userStorage = $user_storage; + $this->eventDispatcher = $event_dispatcher; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $plugin_id, + $plugin_definition, + $configuration['field_definition'], + $configuration['settings'], + $configuration['third_party_settings'], + $container->get('entity_field.manager')->getFieldDefinitions('knowledge_competency', 'knowledge_competency'), + $container->get('config.factory')->get('knowledge.competency.settings'), + $container->get('entity_type.manager')->getStorage('user'), + $container->get('event_dispatcher') + ); + } + + /** + * {@inheritdoc} + */ + public static function defaultSettings(): array { + $setting = ['foo' => 'bar']; + return $setting + parent::defaultSettings(); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state): array { + $element['foo'] = [ + '#type' => 'textfield', + '#title' => $this->t('Foo'), + '#default_value' => $this->getSetting('foo'), + ]; + return $element; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary(): array { + return [ + $this->t('Foo: @foo', ['@foo' => $this->getSetting('foo')]), + ]; + } + + /** + * {@inheritdoc} + */ + public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state): array { + + $element['role'] = [ + '#type' => 'textfield', + '#title' => $this->t('Role'), + '#default_value' => $items[$delta]->role ?? NULL, + ]; + $element['correct'] = [ + '#type' => 'textfield', + '#title' => $this->t('Correct'), + '#default_value' => $items[$delta]->correct ?? NULL, + ]; + $element['total'] = [ + '#type' => 'textfield', + '#title' => $this->t('Total'), + '#default_value' => $items[$delta]->total ?? NULL, + ]; + + $coach = NULL; + if ($items[$delta]->coach) { + $coach = $this->userStorage->load($items[$delta]->coach); + } + $element['proposer'] = [ + '#type' => 'entity_autocomplete', + '#title' => $this->t('Coach'), + '#target_type' => 'user', + '#default_value' => $coach, + ]; + + $approver = NULL; + if ($items[$delta]->approver) { + $approver = $this->userStorage->load($items[$delta]->approver); + } + $element['approver'] = [ + '#type' => 'entity_autocomplete', + '#title' => $this->t('Approver'), + '#target_type' => 'user', + '#default_value' => $approver, + ]; + + return $element; + } + + /** + * {@inheritdoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state): array { + $form_values = $form_state->getValues(); + $entity = $form_state->getFormObject()->getEntity(); + $existing_values = $this->getExistingValues($entity); + $roles = $this->getFieldRoleValues($form_values); + $role_settings = $this->competencySettings->get('roles') ?? []; + $new_values = []; + $completed = []; + foreach ($role_settings as $i => $setting) { + $role = $setting['role']; + if (empty($role)) { + continue; + } + if (!isset($existing_values[$role])) { + $existing_values[$role] = [ + 'correct' => 0, + 'total' => 0, + 'role' => $role, + 'proposer' => NULL, + 'approver' => NULL, + 'proposed' => NULL, + 'approved' => NULL, + ]; + } + $value = [ + 'role' => $role, + 'correct' => $roles[$role]['correct'] ?? 0, + 'total' => $roles[$role]['total'] ?? 0, + 'proposer' => NULL, + 'approver' => NULL, + 'proposed' => $existing_values[$role]['proposed'] ?? NULL, + 'approved' => $existing_values[$role]['approved'] ?? NULL, + ]; + if ($existing_values[$role]['proposer']) { + $value['proposer'] = $this->userStorage->load($existing_values[$role]['proposer']); + } + if ($existing_values[$role]['approver']) { + $value['approver'] = $this->userStorage->load($existing_values[$role]['approver']); + } + $complete = ($value['correct'] == $value['total']); + $existing_complete = $existing_values[$role]['proposer']; + + $new_values[] = $value; + } + + return $new_values; + } + + /** + * Get the field role. + * + * @return array + * The field role. + */ + private function getFieldRoleValues($form_values) { + $roles = []; + foreach ($this->fieldDefinitions as $field_name => $field_definition) { + if ($field_definition->getType() != 'boolean') { + continue; + } + if ($field_name == 'revision_default') { + continue; + } + $role = $field_definition->getThirdPartySetting('knowledge', 'competency_role', '_none'); + if ($role == '_none') { + continue; + } + if (!isset($roles[$role])) { + $roles[$role] = [ + 'correct' => 0, + 'total' => 0, + 'role' => $role, + ]; + } + $roles[$role]['total'] += 1; + if ($form_values[$field_name]['value'] == 1) { + $roles[$role]['correct'] += 1; + } + } + + return $roles; + } + + /** + * Get the existing values. + */ + private function getExistingValues(KnowledgeCompetencyInterface $competency) { + $roles = $competency->get('roles'); + $existing = []; + foreach ($roles as $role) { + $r = $role->role; + $existing[$r] = [ + 'correct' => $role->correct, + 'total' => $role->total, + 'role' => $role->role, + 'proposer' => $role->proposer, + 'approver' => $role->approver, + 'proposed' => $role->proposed, + 'approved' => $role->approved, + ]; + } + + return $existing; + } + +} diff --git a/src/CompetencyAccessControlHandler.php b/src/CompetencyAccessControlHandler.php new file mode 100644 index 0000000000000000000000000000000000000000..7c73711170e25b89a378fb8016c1b8034e425ed6 --- /dev/null +++ b/src/CompetencyAccessControlHandler.php @@ -0,0 +1,81 @@ +<?php + +namespace Drupal\knowledge; + +use Drupal\Core\Access\AccessResult; +use Drupal\Core\Entity\EntityAccessControlHandler; +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Session\AccountInterface; + +/** + * Access controller for the Competency entity. + * + * @see \Drupal\knowledge\Entity\Competency. + */ +class CompetencyAccessControlHandler extends EntityAccessControlHandler { + + /** + * {@inheritdoc} + */ + protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { + /** @var \Drupal\knowledge\KnowledgeCompetencyInterface $entity */ + + switch ($operation) { + + case 'view': + $permissions = [ + 'view any knowledge_competency', + ]; + $own = $entity->getOwnerId() == $account->id(); + if ($own) { + $permissions[] = 'view own knowledge_competency'; + } + + $is_learner = $entity->getOwner()->get('knowledge_coach')->target_id == $account->id(); + if ($is_learner) { + $permissions[] = 'view learner knowledge_competency'; + } + + $is_leader = $entity->getOwner()->get('knowledge_leader')->target_id == $account->id(); + if ($is_leader) { + $permissions[] = 'view follower knowledge_competency'; + } + + return AccessResult::allowedIfHasPermissions($account, $permissions, 'OR'); + + case 'update': + $permissions = []; + $owner = $entity->getOwner(); + $account_id = $account->id(); + + if ($account_id == $owner->id()) { + $permissions[] = 'edit own knowledge_competency'; + } + else { + $permissions[] = 'edit other knowledge_competency'; + } + + $coach_id = $owner->get('knowledge_coach')?->target_id; + if ($account_id == $coach_id) { + $permissions[] = 'edit learner knowledge_competency'; + } + + return AccessResult::allowedIfHasPermissions($account, $permissions, 'OR'); + + case 'delete': + + return AccessResult::allowedIfHasPermission($account, 'administer knowledge_competency'); + } + + // Unknown operation, no opinion. + return AccessResult::neutral(); + } + + /** + * {@inheritdoc} + */ + protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { + return AccessResult::allowedIfHasPermission($account, 'add knowledge_competency'); + } + +} diff --git a/src/KnowledgeCompetencyHtmlRouteProvider.php b/src/CompetencyHtmlRouteProvider.php similarity index 75% rename from src/KnowledgeCompetencyHtmlRouteProvider.php rename to src/CompetencyHtmlRouteProvider.php index 67c5f619d78ebd20b1747063ae04bb852f61e58d..988bb32634eb8c820112b54211d97f1566f97370 100644 --- a/src/KnowledgeCompetencyHtmlRouteProvider.php +++ b/src/CompetencyHtmlRouteProvider.php @@ -12,7 +12,7 @@ use Symfony\Component\Routing\Route; * @see \Drupal\Core\Entity\Routing\AdminHtmlRouteProvider * @see \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider */ -class KnowledgeCompetencyHtmlRouteProvider extends AdminHtmlRouteProvider { +class CompetencyHtmlRouteProvider extends AdminHtmlRouteProvider { /** * {@inheritdoc} @@ -42,6 +42,10 @@ class KnowledgeCompetencyHtmlRouteProvider extends AdminHtmlRouteProvider { $collection->add("$entity_type_id.settings", $settings_form_route); } + if ($role_form_route = $this->getRoleFormRoute($entity_type)) { + $collection->add("$entity_type_id.settings.role", $role_form_route); + } + return $collection; } @@ -60,7 +64,7 @@ class KnowledgeCompetencyHtmlRouteProvider extends AdminHtmlRouteProvider { $route ->setDefaults([ '_title' => "{$entity_type->getLabel()} revisions", - '_controller' => '\Drupal\knowledge\Controller\KnowledgeCompetencyController::revisionOverview', + '_controller' => '\Drupal\knowledge\Controller\CompetencyController::revisionOverview', ]) ->setRequirement('_permission', 'view all competency revisions') ->setOption('_admin_route', TRUE); @@ -85,8 +89,8 @@ class KnowledgeCompetencyHtmlRouteProvider extends AdminHtmlRouteProvider { $route = new Route($entity_type->getLinkTemplate('revision')); $route ->setDefaults([ - '_controller' => '\Drupal\knowledge\Controller\KnowledgeCompetencyController::revisionShow', - '_title_callback' => '\Drupal\knowledge\Controller\KnowledgeCompetencyController::revisionPageTitle', + '_controller' => '\Drupal\knowledge\Controller\CompetencyController::revisionShow', + '_title_callback' => '\Drupal\knowledge\Controller\CompetencyController::revisionPageTitle', ]) ->setRequirement('_permission', 'view all competency revisions') ->setOption('_admin_route', TRUE); @@ -159,20 +163,42 @@ class KnowledgeCompetencyHtmlRouteProvider extends AdminHtmlRouteProvider { * The generated route, if available. */ protected function getSettingsFormRoute(EntityTypeInterface $entity_type) { - if (!$entity_type->getBundleEntityType()) { - $route = new Route("/admin/structure/knowledge/competency/settings"); - $route - ->setDefaults([ - '_form' => 'Drupal\knowledge\Form\KnowledgeCompetencySettingsForm', - '_title' => "Competency", - ]) - ->setRequirement('_permission', $entity_type->getAdminPermission()) - ->setOption('_admin_route', TRUE); - return $route; - } + $route = new Route("/admin/structure/knowledge/competency/settings"); + $route + ->setDefaults([ + '_form' => 'Drupal\knowledge\Form\CompetencySettingsForm', + '_title' => "Competency", + ]) + ->setRequirement('_permission', $entity_type->getAdminPermission()) + ->setOption('_admin_route', TRUE); + + return $route; + + } + + /** + * Gets the settings form route. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type. + * + * @return \Symfony\Component\Routing\Route|null + * The generated route, if available. + */ + protected function getRoleFormRoute(EntityTypeInterface $entity_type) { + + $route = new Route("/admin/structure/knowledge/competency/settings/role"); + $route + ->setDefaults([ + '_form' => 'Drupal\knowledge\Form\CompetencyRoleForm', + '_title' => "Competency", + ]) + ->setRequirement('_permission', $entity_type->getAdminPermission()) + ->setOption('_admin_route', TRUE); + + return $route; - return NULL; } } diff --git a/src/KnowledgeCompetencyListBuilder.php b/src/CompetencyListBuilder.php similarity index 84% rename from src/KnowledgeCompetencyListBuilder.php rename to src/CompetencyListBuilder.php index ecd18440e68df8cbe09cf1347575f3c1dfe1c454..213e45c52127d52257c43593b1f17ce2049096a1 100644 --- a/src/KnowledgeCompetencyListBuilder.php +++ b/src/CompetencyListBuilder.php @@ -11,14 +11,14 @@ use Drupal\Core\Link; * * @ingroup knowledge */ -class KnowledgeCompetencyListBuilder extends EntityListBuilder { +class CompetencyListBuilder extends EntityListBuilder { /** * {@inheritdoc} */ public function buildHeader() { $header['id'] = $this->t('Competency ID'); - $header['name'] = $this->t('Name'); + $header['user'] = $this->t('User'); return $header + parent::buildHeader(); } @@ -28,7 +28,7 @@ class KnowledgeCompetencyListBuilder extends EntityListBuilder { public function buildRow(EntityInterface $entity) { /** @var \Drupal\knowledge\Entity\KnowledgeCompetency $entity */ $row['id'] = $entity->id(); - $row['name'] = Link::createFromRoute( + $row['user'] = Link::createFromRoute( $entity->getOwner()->label(), 'entity.knowledge_competency.edit_form', ['knowledge_competency' => $entity->id()] diff --git a/src/CompetencyStorage.php b/src/CompetencyStorage.php new file mode 100644 index 0000000000000000000000000000000000000000..4f2ab7044fc49359f1790aa11b940d696d2d46df --- /dev/null +++ b/src/CompetencyStorage.php @@ -0,0 +1,38 @@ +<?php + +namespace Drupal\knowledge; + +use Drupal\Core\Entity\Sql\SqlContentEntityStorage; +use Drupal\Core\Session\AccountInterface; + +/** + * Defines the storage handler class for Competency entities. + * + * This extends the base storage class, adding required special handling for + * Competency entities. + * + * @ingroup knowledge + */ +class CompetencyStorage extends SqlContentEntityStorage implements KnowledgeCompetencyStorageInterface { + + /** + * {@inheritdoc} + */ + public function revisionIds(KnowledgeCompetencyInterface $entity) { + return $this->database->query( + 'SELECT vid FROM {knowledge_competency_revision} WHERE id=:id ORDER BY vid', + [':id' => $entity->id()] + )->fetchCol(); + } + + /** + * {@inheritdoc} + */ + public function userRevisionIds(AccountInterface $account) { + return $this->database->query( + 'SELECT vid FROM {knowledge_competency_field_revision} WHERE uid = :uid ORDER BY vid', + [':uid' => $account->id()] + )->fetchCol(); + } + +} diff --git a/src/Controller/KnowledgeCompetencyController.php b/src/Controller/CompetencyController.php similarity index 66% rename from src/Controller/KnowledgeCompetencyController.php rename to src/Controller/CompetencyController.php index 988cb52c62715b90333ac995811b7df7fb088437..8624d43f36e183ee20fa917395bb112ef0ccc483 100644 --- a/src/Controller/KnowledgeCompetencyController.php +++ b/src/Controller/CompetencyController.php @@ -5,22 +5,24 @@ namespace Drupal\knowledge\Controller; use Drupal\Component\Utility\Xss; use Drupal\Core\Access\AccessResult; use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Link; +use Drupal\Core\Render\Renderer; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Url; use Drupal\Core\Utility\TableSort; -use Drupal\knowledge\Entity\KnowledgeCompetencyInterface; +use Drupal\knowledge\KnowledgeCompetencyInterface; +use Drupal\knowledge\KnowledgeCompetencyServiceInterface; +use Drupal\user\UserInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** - * Class KnowledgeCompetencyController. - * - * Returns responses for Competency routes. + * Competency Controller. */ -class KnowledgeCompetencyController extends ControllerBase implements ContainerInjectionInterface { +class CompetencyController extends ControllerBase implements ContainerInjectionInterface { /** * The date formatter. @@ -36,14 +38,38 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI */ protected $renderer; + /** + * The competency service. + * + * @var \Drupal\knowledge\KnowledgeCompetencyServiceInterface + */ + protected $competency; + /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { - $instance = parent::create($container); - $instance->dateFormatter = $container->get('date.formatter'); - $instance->renderer = $container->get('renderer'); - return $instance; + return new static( + $container->get('date.formatter'), + $container->get('renderer'), + $container->get('knowledge.competency') + ); + } + + /** + * Constructs Competency Controller object. + * + * @param \Drupal\Core\Datetime\DateFormatter $date_formatter + * The date formatter. + * @param \Drupal\Core\Render\Renderer $renderer + * The renderer. + * @param \Drupal\knowledge\KnowledgeCompetencyServiceInterface $competency + * The competency service. + */ + public function __construct(DateFormatter $date_formatter, Renderer $renderer, KnowledgeCompetencyServiceInterface $competency) { + $this->dateFormatter = $date_formatter; + $this->renderer = $renderer; + $this->competency = $competency; } /** @@ -58,7 +84,7 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI public function revisionShow($knowledge_competency_revision) { /** @var \Drupal\knowledge\KnowledgeCompetencyStorageInterface $competency_storage */ $competency_storage = $this->entityTypeManager()->getStorage('knowledge_competency'); - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $knowledge_competency */ + /** @var \Drupal\knowledge\KnowledgeCompetencyInterface $knowledge_competency */ $knowledge_competency = $competency_storage->loadRevision($knowledge_competency_revision); $view_builder = $this->entityTypeManager()->getViewBuilder('knowledge_competency'); @@ -77,7 +103,7 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI public function revisionPageTitle($knowledge_competency_revision) { /** @var \Drupal\knowledge\KnowledgeCompetencyStorageInterface $competency_storage */ $competency_storage = $this->entityTypeManager()->getStorage('knowledge_competency'); - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $knowledge_competency */ + /** @var \Drupal\knowledge\KnowledgeCompetencyInterface $knowledge_competency */ $knowledge_competency = $competency_storage->loadRevision($knowledge_competency_revision); return $this->t('Revision of %title from %date', [ @@ -89,7 +115,7 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI /** * Generates an overview table of older revisions of a Competency. * - * @param \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $knowledge_competency + * @param \Drupal\knowledge\KnowledgeCompetencyInterface $knowledge_competency * A Competency object. * * @return array @@ -103,8 +129,8 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI $build['#title'] = $this->t('Revisions for %title', ['%title' => $knowledge_competency->label()]); $header = [$this->t('Revision'), $this->t('Operations')]; - $revert_permission = (($account->hasPermission("revert all competency revisions") || $account->hasPermission('administer competency entities'))); - $delete_permission = (($account->hasPermission("delete all competency revisions") || $account->hasPermission('administer competency entities'))); + $revert_permission = (($account->hasPermission("revert all competency revisions") || $account->hasPermission('administer knowledge_competency'))); + $delete_permission = (($account->hasPermission("delete all competency revisions") || $account->hasPermission('administer knowledge_competency'))); $rows = []; @@ -113,7 +139,7 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI $latest_revision = TRUE; foreach (array_reverse($vids) as $vid) { - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $revision */ + /** @var \Drupal\knowledge\KnowledgeCompetencyInterface $revision */ $revision = $knowledge_competency_storage->loadRevision($vid); $username = [ '#theme' => 'username', @@ -206,17 +232,30 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI /** * Returns the competency the belongs to the user. + * + * @param \Drupal\user\UserInterface $user + * The user to get the competency for. */ - public function userCompetency($user) { + public function userCompetency(UserInterface $user) { + $user_id = $user->id(); $account = $this->currentUser(); - $view_builder = $this->entityTypeManager()->getViewBuilder('knowledge_competency'); - $form_builder = $this->entityFormBuilder(); - $competency = $this->getCompetency($user); + if ($user->get('knowledge_coach')->isEmpty()) { + return [ + '#markup' => $this->t('@username does not have a coach.', ['@username' => $user->getDisplayName()]), + ]; + } + $is_self = $account->id() == $user_id; + $is_learner = $account->id() == $user->get('knowledge_coach')->target_id || $account->id() == 1; + + $competency = $this->competency->getUserCompetency($user_id); - if ($account->hasPermission('edit competency entities')) { + if ($account->hasPermission('edit learner knowledge_competency')) { + $form_builder = $this->entityFormBuilder(); return $form_builder->getForm($competency); } + $view_builder = $this->entityTypeManager()->getViewBuilder('knowledge_competency'); + return $view_builder->view($competency); } @@ -231,20 +270,44 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI * @return \Drupal\Core\Access\AccessResultInterface * The access result. */ - public function accessCompetencyApproval(AccountInterface $account, int $user) { + public function accessUserCompetency(AccountInterface $account, UserInterface $user) { - $account_id = $account->id(); - if ($account_id == 1) { + $competency = $this->competency->getUserCompetency($user->id()); + + if ($competency->access('view', $account)) { + return AccessResult::allowed(); + } + if ($competency->access('update', $account)) { return AccessResult::allowed(); } - $competency = $this->getCompetency($user); - if (!$competency->isPendingContributor() && !$competency->isPendingPublisher()) { + + return AccessResult::neutral(); + } + + /** + * Checks access for a specific request. + * + * @param \Drupal\Core\Session\AccountInterface $account + * Run access checks for this account (leader). + * @param \Drupal\user\UserInterface $user + * The user the competency belongs to. + * + * @return \Drupal\Core\Access\AccessResultInterface + * The access result. + */ + public function accessCompetencyApproval(AccountInterface $account, UserInterface $user) { + $user_id = $user->id(); + $competency = $this->competency->getUserCompetency($user_id); + $is_pending = $competency->isPending(); + if (!$is_pending) { throw new NotFoundHttpException(); } - $user = $this->entityTypeManager() - ->getStorage('user') - ->load($user); + $account_id = $account->id(); + if ($account_id == 1) { + return AccessResult::allowed(); + } + $leader_id = $user->knowledge_leader->target_id; return AccessResult::allowedIf($account_id == $leader_id); @@ -252,47 +315,52 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI /** * The table report of competencies. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request object. */ public function competencySummaryReport(Request $request) { - $groups = field_group_info_groups('knowledge_competency', 'knowledge_competency', 'form', 'default'); - $result = views_get_view_result('competency_progress'); + $role_storage = $this->entityTypeManager()->getStorage('user_role'); + $fields_definitions = \Drupal::service('entity_field.manager') + ->getFieldDefinitions('knowledge_competency', 'knowledge_competency'); + $fields = []; + foreach ($fields_definitions as $field_id => $field_definition) { + if (get_class($field_definition) != 'Drupal\field\Entity\FieldConfig') { + continue; + } + $role = $field_definition->getThirdPartySetting('knowledge', 'competency_role', '_none'); + if ($role == '_none') { + continue; + } + $fields[$field_id] = $role; + } + + $result = views_get_view_result('knowledge_competency_progress'); + if (empty($result)) { + return []; + } $result = $result[0]; $entity = $result->_entity; + if (!$entity) { + return []; + } $total = $result->id; $rows = []; $order = 0; - $candidate = 'Paddler'; - $contributor = 'Rider'; - $publisher = 'Pro'; + $i = 0; - foreach ($groups['group_candidate']->children as $field) { - $competency = $entity->$field->getFieldDefinition()->getLabel(); - $key = 'knowledge_competency__' . $field . '_' . $field . '_value'; - $key = substr($key, 0, 60); - $value = $result->$key; - $percentage = (int) (100 * ($value / $total)); - $i += 1; - $rows[] = [$i, $candidate, $competency, $percentage]; - } - foreach ($groups['group_contributor']->children as $field) { - $competency = $entity->$field->getFieldDefinition()->getLabel(); - $key = 'knowledge_competency__' . $field . '_' . $field . '_value'; - $key = substr($key, 0, 60); - $value = $result->$key; - $percentage = (int) (100 * ($value / $total)); - $i += 1; - $rows[] = [$i, $contributor, $competency, $percentage]; - } - foreach ($groups['group_publisher']->children as $field) { + foreach ($fields as $field => $role_id) { + $role = $role_storage->load($role_id); $competency = $entity->$field->getFieldDefinition()->getLabel(); $key = 'knowledge_competency__' . $field . '_' . $field . '_value'; $key = substr($key, 0, 60); $value = $result->$key; $percentage = (int) (100 * ($value / $total)); $i += 1; - $rows[] = [$i, $publisher, $competency, $percentage]; + $rows[] = [$i, $role->label(), $competency, $percentage]; } + $header = [ 'id' => [ 'data' => $this->t('Id'), @@ -348,6 +416,11 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI $data['labels'][] = $competency; $data['datasets'][0]['data'][] = $percent; + if (!isset($colors[$role])) { + $color_array = $this->getColor($role); + $colors[$role] = 'rgba(' . $color_array[0] . ', ' . $color_array[1] . ', ' . $color_array[2]; + } + $data['datasets'][0]['backgroundColor'][] = $colors[$role] . ',.4)'; $data['datasets'][0]['borderColor'][] = $colors[$role] . ',.9)'; } @@ -383,6 +456,11 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI /** * Custom data sort. + * + * @param string $key + * The key to sort by. + * @param bool $desc + * Whether to sort in descending order. */ private function tableSorter($key, $desc) { return function ($a, $b) use ($key, $desc) { @@ -395,28 +473,19 @@ class KnowledgeCompetencyController extends ControllerBase implements ContainerI } /** - * Get the user's competency. + * Get a color based on a number. */ - protected function getCompetency($user_id) { - $competency = NULL; - $storage = $this->entityTypeManager() - ->getStorage('knowledge_competency'); - $query = $storage->getQuery(); - $result = $query - ->condition('user_id', $user_id) - ->accessCheck(FALSE) - ->execute(); - - if (count($result) == 1) { - $competency = $storage->load(current($result)); - } - if (count($result) == 0) { - $competency = $storage->create([ - 'user_id' => $user_id, - ]); - } - - return $competency; + public function getColor($num) { + // Modify 'color' to get a different palette. + $hash = md5('color' . $num); + return [ + // R. + hexdec(substr($hash, 0, 2)), + // G. + hexdec(substr($hash, 2, 2)), + // B. + hexdec(substr($hash, 4, 2)), + ]; } } diff --git a/src/Entity/KnowledgeCompetency.php b/src/Entity/Competency.php similarity index 65% rename from src/Entity/KnowledgeCompetency.php rename to src/Entity/Competency.php index b8103e93874e607ed6e8cefc0443f670c625cdac..c6e409250cfb2a7bc25762e495f5c93a380482e7 100644 --- a/src/Entity/KnowledgeCompetency.php +++ b/src/Entity/Competency.php @@ -8,10 +8,13 @@ use Drupal\Core\Entity\EntityChangedTrait; use Drupal\Core\Entity\EntityConstraintViolationList; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeInterface; -use Drupal\Core\Entity\RevisionableInterface; use Drupal\Core\Entity\RevisionLogEntityTrait; use Drupal\Core\Entity\RevisionLogInterface; +use Drupal\Core\Entity\RevisionableInterface; use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\Field\FieldStorageDefinitionInterface; +use Drupal\knowledge\KnowledgeCompetencyInterface; +use Drupal\knowledge_field\Helper\CompetencyField; use Drupal\user\UserInterface; use Symfony\Component\Validator\ConstraintViolation; @@ -24,29 +27,29 @@ use Symfony\Component\Validator\ConstraintViolation; * id = "knowledge_competency", * label = @Translation("Competency"), * handlers = { - * "storage" = "Drupal\knowledge\KnowledgeCompetencyStorage", + * "storage" = "Drupal\knowledge\CompetencyStorage", * "view_builder" = "Drupal\Core\Entity\EntityViewBuilder", - * "list_builder" = "Drupal\knowledge\KnowledgeCompetencyListBuilder", - * "views_data" = "Drupal\knowledge\Entity\KnowledgeCompetencyViewsData", + * "list_builder" = "Drupal\knowledge\CompetencyListBuilder", + * "views_data" = "Drupal\knowledge\Entity\CompetencyViewsData", * * "form" = { - * "default" = "Drupal\knowledge\Form\KnowledgeCompetencyForm", - * "add" = "Drupal\knowledge\Form\KnowledgeCompetencyForm", - * "edit" = "Drupal\knowledge\Form\KnowledgeCompetencyForm", - * "delete" = "Drupal\knowledge\Form\KnowledgeCompetencyDeleteForm", - * "approve" = "Drupal\knowledge\Form\KnowledgeCompetencyApproveForm", + * "default" = "Drupal\knowledge\Form\CompetencyForm", + * "add" = "Drupal\knowledge\Form\CompetencyForm", + * "edit" = "Drupal\knowledge\Form\CompetencyForm", + * "delete" = "Drupal\knowledge\Form\CompetencyDeleteForm", + * "approve" = "Drupal\knowledge\Form\CompetencyApproveForm", * }, * "route_provider" = { - * "html" = "Drupal\knowledge\KnowledgeCompetencyHtmlRouteProvider", + * "html" = "Drupal\knowledge\CompetencyHtmlRouteProvider", * }, - * "access" = "Drupal\knowledge\KnowledgeCompetencyAccessControlHandler", + * "access" = "Drupal\knowledge\CompetencyAccessControlHandler", * }, * base_table = "knowledge_competency", * revision_table = "knowledge_competency_revision", * revision_data_table = "knowledge_competency_field_revision", * show_revision_ui = TRUE, * translatable = FALSE, - * admin_permission = "administer competency entities", + * admin_permission = "administer knowledge_competency", * entity_keys = { * "id" = "id", * "revision" = "vid", @@ -73,7 +76,7 @@ use Symfony\Component\Validator\ConstraintViolation; * field_ui_base_route = "knowledge_competency.settings" * ) */ -class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInterface, RevisionLogInterface, KnowledgeCompetencyInterface { +class Competency extends ContentEntityBase implements EntityChangedInterface, RevisionLogInterface, KnowledgeCompetencyInterface { use EntityChangedTrait; use RevisionLogEntityTrait; @@ -98,6 +101,7 @@ class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInte * {@inheritdoc} */ public function preSave(EntityStorageInterface $storage) { + $this->ensureRoles(); parent::preSave($storage); $this->setNewRevision(); // If no revision author has been set explicitly, @@ -106,43 +110,67 @@ class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInte $this->setRevisionUserId($this->getOwnerId()); } - $groups = field_group_info_groups('knowledge_competency', 'knowledge_competency', 'form', 'default'); - $candidate_correct = 0; - $candidate_total = 0; - foreach ($groups['group_candidate']->children as $field) { - $candidate_total += 1; - if ($this->{$field}->value) { - $candidate_correct += 1; - } + $roles = $this->get('roles'); + $total = 0; + $correct = 0; + foreach ($roles as $role) { + $total += $role->total; + $correct += $role->correct; } - $contributor_correct = 0; - $contributor_total = 0; - foreach ($groups['group_contributor']->children as $field) { - $contributor_total += 1; - if ($this->{$field}->value) { - $contributor_correct += 1; - } + + $this->set('correct', $correct); + $this->set('total', $total); + + $completed = NULL; + if ($correct == $total) { + $completed = time(); } - $publisher_correct = 0; - $publisher_total = 0; - foreach ($groups['group_publisher']->children as $field) { - $publisher_total += 1; - if ($this->{$field}->value) { - $publisher_correct += 1; - } + $this->set('completed', $completed); + + $this->setLegacyFields(); + + $roles = $this->get('roles'); + $orginal_roles = $this->original?->get('roles')->getValue() ?? []; + \Drupal::service('knowledge.competency')->doPreSave($roles, $orginal_roles); + } + + /** + * {@inheritdoc} + */ + public function postSave(EntityStorageInterface $storage, $update = TRUE) { + parent::postSave($storage, $update); + // Get the orginals values. + $orginal_roles = $this->original?->get('roles')->getValue() ?? []; + $roles = $this->get('roles')->getValue(); + $owner = $this->getOwner(); + \Drupal::service('knowledge.competency')->doPostSave($owner, $roles, $orginal_roles); + + } + + /** + * Ensure all roles are present. + */ + private function ensureRoles() { + $roles = $this->get('roles'); + $definitions = $this->getFieldDefinitions(); + $role_fields = CompetencyField::roleFields($definitions); + + foreach ($roles as $role) { + unset($role_fields[$role->role]); } - $this->set('candidate_correct', $candidate_correct); - $this->set('candidate_total', $candidate_total); - $this->set('contributor_correct', $contributor_correct); - $this->set('contributor_total', $contributor_total); - $this->set('publisher_correct', $publisher_correct); - $this->set('publisher_total', $publisher_total); + foreach ($role_fields as $role => $field) { + $roles->appendItem([ + 'role' => $role, + 'correct' => 0, + 'total' => 0, + 'proposed' => NULL, + 'approved' => NULL, + 'proposer' => NULL, + 'approver' => NULL, + ]); + } - $correct = $candidate_correct + $contributor_correct + $publisher_correct; - $total = $candidate_total + $contributor_total + $publisher_total; - $this->set('correct', $correct); - $this->set('total', $total); } /** @@ -231,32 +259,33 @@ class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInte 'placeholder' => '', ], ]) - ->setDisplayConfigurable('form', TRUE) ->setDisplayConfigurable('view', TRUE); - $fields['contributor_coach'] = BaseFieldDefinition::create('entity_reference') - ->setLabel(t('Coach')) - ->setDescription(t('The user who suggests promotion to contributor.')) - ->setRevisionable(FALSE) - ->setSetting('target_type', 'user') - ->setSetting('handler', 'default') + $fields['roles'] = BaseFieldDefinition::create('knowledge_competency_role') + ->setLabel(t('Roles')) + ->setDescription(t('The roles of the user.')) + ->setRevisionable(TRUE) + ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) ->setDisplayOptions('view', [ 'label' => 'hidden', - 'type' => 'author', + 'type' => 'knowledge_competency_role', 'weight' => 0, ]) ->setDisplayOptions('form', [ - 'type' => 'entity_reference_autocomplete', + 'type' => 'knowledge_competency_role', 'weight' => 5, - 'settings' => [ - 'match_operator' => 'CONTAINS', - 'size' => '60', - 'autocomplete_type' => 'tags', - 'placeholder' => '', - ], ]) - ->setDisplayConfigurable('form', TRUE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('view', TRUE) + ->setDisplayConfigurable('form', TRUE); + + $fields['contributor_coach'] = BaseFieldDefinition::create('entity_reference') + ->setLabel(t('Coach')) + ->setDescription(t('The user who suggests promotion to contributor.')) + ->setRevisionable(FALSE) + ->setSetting('target_type', 'user') + ->setSetting('handler', 'default') + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['contributor_leader'] = BaseFieldDefinition::create('entity_reference') ->setLabel(t('Leader')) @@ -264,23 +293,8 @@ class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInte ->setRevisionable(FALSE) ->setSetting('target_type', 'user') ->setSetting('handler', 'default') - ->setDisplayOptions('view', [ - 'label' => 'hidden', - 'type' => 'author', - 'weight' => 0, - ]) - ->setDisplayOptions('form', [ - 'type' => 'entity_reference_autocomplete', - 'weight' => 5, - 'settings' => [ - 'match_operator' => 'CONTAINS', - 'size' => '60', - 'autocomplete_type' => 'tags', - 'placeholder' => '', - ], - ]) - ->setDisplayConfigurable('form', TRUE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['publisher_coach'] = BaseFieldDefinition::create('entity_reference') ->setLabel(t('Coach')) @@ -288,23 +302,8 @@ class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInte ->setRevisionable(FALSE) ->setSetting('target_type', 'user') ->setSetting('handler', 'default') - ->setDisplayOptions('view', [ - 'label' => 'hidden', - 'type' => 'author', - 'weight' => 0, - ]) - ->setDisplayOptions('form', [ - 'type' => 'entity_reference_autocomplete', - 'weight' => 5, - 'settings' => [ - 'match_operator' => 'CONTAINS', - 'size' => '60', - 'autocomplete_type' => 'tags', - 'placeholder' => '', - ], - ]) - ->setDisplayConfigurable('form', TRUE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['publisher_leader'] = BaseFieldDefinition::create('entity_reference') ->setLabel(t('Leader')) @@ -312,95 +311,101 @@ class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInte ->setRevisionable(FALSE) ->setSetting('target_type', 'user') ->setSetting('handler', 'default') - ->setDisplayOptions('view', [ - 'label' => 'hidden', - 'type' => 'author', - 'weight' => 0, - ]) - ->setDisplayOptions('form', [ - 'type' => 'entity_reference_autocomplete', - 'weight' => 5, - 'settings' => [ - 'match_operator' => 'CONTAINS', - 'size' => '60', - 'autocomplete_type' => 'tags', - 'placeholder' => '', - ], - ]) - ->setDisplayConfigurable('form', TRUE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['contributor_proposed'] = BaseFieldDefinition::create('timestamp') ->setLabel(t('Proposed')) ->setDescription(t('The time that the entity was created.')) ->setDisplayConfigurable('form', FALSE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('view', FALSE); $fields['contributor_approved'] = BaseFieldDefinition::create('timestamp') ->setLabel(t('Approved')) ->setDescription(t('The time that the entity was created.')) ->setDisplayConfigurable('form', FALSE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('view', FALSE); $fields['publisher_proposed'] = BaseFieldDefinition::create('timestamp') ->setLabel(t('Proposed')) ->setDescription(t('The time that the entity was created.')) ->setDisplayConfigurable('form', FALSE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('view', FALSE); $fields['publisher_approved'] = BaseFieldDefinition::create('timestamp') ->setLabel(t('Approved')) ->setDescription(t('The time that the entity was created.')) ->setDisplayConfigurable('form', FALSE) - ->setDisplayConfigurable('view', TRUE); + ->setDisplayConfigurable('view', FALSE); $fields['candidate_correct'] = BaseFieldDefinition::create('integer') ->setLabel(t('Correct candidate competencies')) ->setDescription(t('The number of correct candidate items.')) - ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRequired(FALSE) + ->setRevisionable(FALSE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['candidate_total'] = BaseFieldDefinition::create('integer') ->setLabel(t('Total candidate competencies')) ->setDescription(t('The total candidate items.')) - ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRequired(FALSE) + ->setRevisionable(FALSE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['contributor_correct'] = BaseFieldDefinition::create('integer') ->setLabel(t('Correct contributor competencies')) ->setDescription(t('The number of correct contributor items.')) - ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRequired(FALSE) + ->setRevisionable(FALSE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['contributor_total'] = BaseFieldDefinition::create('integer') ->setLabel(t('Total contributor competencies')) ->setDescription(t('The total contributor items.')) ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRevisionable(TRUE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['publisher_correct'] = BaseFieldDefinition::create('integer') ->setLabel(t('Correct publisher competencies')) ->setDescription(t('The number of correct publisher items.')) ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRevisionable(TRUE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['publisher_total'] = BaseFieldDefinition::create('integer') ->setLabel(t('Total publisher competencies')) ->setDescription(t('The total publisher items.')) ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRevisionable(TRUE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', FALSE); $fields['correct'] = BaseFieldDefinition::create('integer') ->setLabel(t('Correct competencies')) ->setDescription(t('The number of correct items.')) ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRevisionable(TRUE) + ->setDisplayConfigurable('view', TRUE); $fields['total'] = BaseFieldDefinition::create('integer') ->setLabel(t('Total competencies')) ->setDescription(t('The total competencies items.')) ->setRequired(TRUE) - ->setRevisionable(TRUE); + ->setRevisionable(TRUE) + ->setDisplayConfigurable('view', TRUE); + + $fields['completed'] = BaseFieldDefinition::create('timestamp') + ->setLabel(t('Completed')) + ->setDescription(t('The time that correct = total.')) + ->setRevisionable(FALSE) + ->setDisplayConfigurable('form', FALSE) + ->setDisplayConfigurable('view', TRUE); $fields['created'] = BaseFieldDefinition::create('created') ->setLabel(t('Created')) @@ -442,22 +447,46 @@ class KnowledgeCompetency extends ContentEntityBase implements EntityChangedInte /** * {@inheritdoc} */ - public function isPendingContributor(): bool { - return !$this->isPendingPublisher() && $this->contributor_coach->target_id != NULL && $this->contributor_leader->target_id == NULL; - } + public function isPending(): ?string { + $roles = $this->get('roles'); + foreach ($roles as $role) { + if ($role->isPending()) { + return $role->role; + } + } - /** - * {@inheritdoc} - */ - public function isPendingPublisher(): bool { - return $this->publisher_coach->target_id != NULL && $this->publisher_leader->target_id == NULL; + return FALSE; } /** - * {@inheritdoc} + * Set legacy fields. */ - public function isPending(): bool { - return $this->isPendingContributor() || $this->isPendingPublisher(); + private function setLegacyFields() { + $legacy_roles = [ + 'knowledge_candidate', + 'knowledge_contributor', + 'knowledge_publisher', + ]; + $roles = $this->get('roles'); + foreach ($roles as $role) { + $name = $role->role; + if (!in_array($name, $legacy_roles)) { + continue; + } + $name = str_replace('knowledge_', '', $name); + + $this->set($name . '_correct', $role->correct); + $this->set($name . '_total', $role->total); + + if ($name == 'candidate') { + continue; + } + + $this->set($name . '_proposed', $role->proposed); + $this->set($name . '_approved', $role->approved); + $this->set($name . '_coach', $role->proposer); + $this->set($name . '_leader', $role->approver); + } } } diff --git a/src/Entity/KnowledgeCompetencyViewsData.php b/src/Entity/CompetencyViewsData.php similarity index 85% rename from src/Entity/KnowledgeCompetencyViewsData.php rename to src/Entity/CompetencyViewsData.php index 3ae535ae6f66fa2d732d0358e6309f88a97f7439..1b487db03c26f61e3c826b948f69024a62860059 100644 --- a/src/Entity/KnowledgeCompetencyViewsData.php +++ b/src/Entity/CompetencyViewsData.php @@ -7,7 +7,7 @@ use Drupal\views\EntityViewsData; /** * Provides Views data for Competency entities. */ -class KnowledgeCompetencyViewsData extends EntityViewsData { +class CompetencyViewsData extends EntityViewsData { /** * {@inheritdoc} diff --git a/src/Form/CompetencyApproveForm.php b/src/Form/CompetencyApproveForm.php new file mode 100644 index 0000000000000000000000000000000000000000..675c6046e958b7495a72829d61e32fbe9b74c04c --- /dev/null +++ b/src/Form/CompetencyApproveForm.php @@ -0,0 +1,234 @@ +<?php + +namespace Drupal\knowledge\Form; + +use Drupal\Component\Datetime\TimeInterface; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Form\ConfirmFormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Session\AccountProxyInterface; +use Drupal\Core\Url; +use Drupal\knowledge\KnowledgeCompetencyServiceInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Provides the knowledge delete confirmation form. + * + * @internal + */ +class CompetencyApproveForm extends ConfirmFormBase { + + /** + * The knowledge competency. + * + * @var \Drupal\knowledge\KnowledgeCompetencyInterface + */ + protected $competency; + + /** + * The user to be promoted. + * + * @var \Drupal\user\UserInterface + */ + protected $learner; + + /** + * The role to ne promoted to. + * + * @var \Drupal\user\RoleInterface + */ + protected $role; + + /** + * The current user account. + * + * @var \Drupal\Core\Session\AccountProxyInterface + */ + protected $account; + + /** + * The time service. + * + * @var \Drupal\Component\Datetime\TimeInterface + */ + protected $time; + + /** + * The competency storage service. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $competencyStorage; + + /** + * The competency service. + * + * @var \Drupal\knowledge\KnowledgeCompetencyServiceInterface + */ + protected $competencyService; + + /** + * The user role storage service. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $userRoleStorage; + + /** + * Constructs a new CompetencyApproveForm object. + * + * @param \Drupal\Core\Session\AccountProxyInterface $account + * The current user account. + * @param \Drupal\Component\Datetime\TimeInterface $time + * The time service. + * @param \Drupal\Core\Entity\EntityStorageInterface $competency_storage + * The competency storage service. + * @param \Drupal\Core\Entity\EntityStorageInterface $user_role_storage + * The user role storage service. + * @param \Drupal\knowledge\KnowledgeCompetencyServiceInterface $competency_service + * The competency service. + */ + public function __construct( + AccountProxyInterface $account, + TimeInterface $time, + EntityStorageInterface $competency_storage, + EntityStorageInterface $user_role_storage, + KnowledgeCompetencyServiceInterface $competency_service, + ) { + $this->account = $account; + $this->time = $time; + $this->competencyStorage = $competency_storage; + $this->userRoleStorage = $user_role_storage; + $this->competencyService = $competency_service; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('current_user'), + $container->get('datetime.time'), + $container->get('entity_type.manager')->getStorage('knowledge_competency'), + $container->get('entity_type.manager')->getStorage('user_role'), + $container->get('knowledge.competency'), + ); + } + + /** + * {@inheritdoc} + */ + public function getFormId() : string { + return "confirm_knowledge_competency_approve_form"; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state, $user = '') { + $competency = $this->competencyService->getUserCompetency($user->id()); + $this->setCompetency($competency); + $form = parent::buildForm($form, $form_state); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return $this->t('Promote'); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl() { + return Url::fromRoute('entity.user.knowledge_competency', [ + 'user' => $this->competency->getOwnerId(), + ]); + } + + /** + * {@inheritdoc} + */ + protected function getRedirectUrl() { + return $this->getCancelUrl(); + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + return $this->t('Do you want to promote the user?'); + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + + $username = $this->learner ? $this->learner->label() : '<unknown>'; + $role = $this->role ? $this->role->label() : '<unknown>'; + + $p = [ + '@username' => $username, + '@role' => $role, + ]; + return $this->t('Do you want to promote @username to a @role?', $p); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $competency = $this->competency; + $learner = $this->learner; + $role = $this->role->id(); + + if (!$this->competencyService->hasRoleOrBetter($role, $learner->getRoles())) { + $learner->addRole($role); + $learner->save(); + $this->messenger()->addMessage($this->t('@user was promoted to @role.', [ + '@role' => $this->role->label(), + '@user' => $learner->getDisplayName(), + ])); + } + + $pending_role = $competency->isPending(); + if ($pending_role == FALSE) { + return; + } + foreach ($competency->get('roles') as $role) { + if ($role->role == $pending_role) { + $role->approved = $this->time->getRequestTime(); + $role->approver = $this->account->id(); + } + } + $competency->save(); + + $form_state->setRedirect('entity.user.knowledge_competency', [ + 'user' => $this->competency->getOwnerId(), + ]); + } + + /** + * Sets the competency pending approval. + */ + public function setCompetency($competency) { + $this->competency = $competency; + $this->learner = $competency->getOwner(); + + $role_id = $competency->isPending(); + if (!$role_id) { + return; + } + + $promotion_role = $this->competencyService->getPromotionRole($role_id); + if (!$promotion_role) { + return; + } + $this->role = $this->userRoleStorage->load($promotion_role); + } + +} diff --git a/src/Form/CompetencyDeleteForm.php b/src/Form/CompetencyDeleteForm.php new file mode 100644 index 0000000000000000000000000000000000000000..b60b7bf4e903d6dfc9e83c3427c132bbe0a71f29 --- /dev/null +++ b/src/Form/CompetencyDeleteForm.php @@ -0,0 +1,26 @@ +<?php + +namespace Drupal\knowledge\Form; + +use Drupal\Core\Entity\ContentEntityDeleteForm; +use Drupal\Core\Url; + +/** + * Provides a form for deleting Competency entities. + * + * @ingroup knowledge + */ +class CompetencyDeleteForm extends ContentEntityDeleteForm { + + /** + * {@inheritdoc} + */ + protected function getRedirectUrl() { + $entity = $this->getEntity(); + $owner = $entity->getOwner(); + + return Url::fromRoute('entity.user.knowledge_competency', ['user' => $owner->id()]); + + } + +} diff --git a/src/Form/CompetencyForm.php b/src/Form/CompetencyForm.php new file mode 100644 index 0000000000000000000000000000000000000000..80a003ef5dc5beb8aee54641aa0ca57dcd16b8a1 --- /dev/null +++ b/src/Form/CompetencyForm.php @@ -0,0 +1,257 @@ +<?php + +namespace Drupal\knowledge\Form; + +use Drupal\Core\Entity\ContentEntityForm; +use Drupal\Core\Form\FormStateInterface; +use Drupal\knowledge_field\Helper\CompetencyField; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Form controller for Competency edit forms. + * + * @ingroup knowledge + */ +class CompetencyForm extends ContentEntityForm { + + /** + * The current user account. + * + * @var \Drupal\Core\Session\AccountProxyInterface + */ + protected $account; + + /** + * The knowledge settings config. + * + * @var \Drupal\Core\Config\Config + */ + protected $settings; + + /** + * The database connection. + * + * @var \Drupal\Core\Database\Connection + */ + protected $database; + + /** + * The date formatter service. + * + * @var \Drupal\Core\Datetime\DateFormatter + */ + protected $dateFormatter; + + /** + * The user role storage service. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $roleStorage; + + /** + * The field group info array. + * + * @var array + */ + protected $groups; + + /** + * The Renderer service. + * + * @var \Drupal\Core\Render\Renderer + */ + protected $render; + + /** + * The field definitions for the knowledge competency entity. + * + * @var \Drupal\Core\Field\FieldDefinitionInterface[] + */ + protected $definitions; + + /** + * The competency service. + * + * @var \Drupal\knowledge\KnowledgeCompetencyServiceInterface + */ + protected $competencyService; + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + // Instantiates this form class. + $instance = parent::create($container); + $instance->account = $container->get('current_user'); + $instance->roleStorage = $container->get('entity_type.manager')->getStorage('user_role'); + $instance->settings = $container->get('config.factory')->get('knowledge.competency.settings'); + $instance->competencyService = $container->get('knowledge.competency'); + $instance->dateFormatter = $container->get('date.formatter'); + $instance->time = $container->get('datetime.time'); + $instance->render = $container->get('renderer'); + $instance->definitions = $container->get('entity_field.manager')->getFieldDefinitions('knowledge_competency', 'knowledge_competency'); + return $instance; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + $form = parent::buildForm($form, $form_state); + + $this->addRoleTabs($form); + $this->buildCompetency($form); + + // In several places within this function, we vary $form on: + // - The current user's permissions. + // - Whether the current user is authenticated or anonymous. + // - The 'user.settings' configuration. + // - The knowledge field's definition. + $form['#cache']['contexts'][] = 'user'; + $form['#cache']['contexts'][] = 'user.roles:authenticated'; + + $form['user_id']['#type'] = 'hidden'; + + $form['#attached']['library'][] = 'knowledge/competency_form'; + + return $form; + } + + /** + * Adds the role tabs. + * + * @param array $form + * The form. + */ + private function addRoleTabs(array &$form) { + $roles_weight = $form['roles']['widget'][0]['#weight']; + $form['skills'] = [ + "#type" => "vertical_tabs", + "#weight" => $roles_weight, + "#default_tab" => "edit-knowledge-publisher", + ]; + $competency_roles = $this->competencyService->getRoleIds(); + $roles = $this->roleStorage->loadMultiple($competency_roles); + foreach ($competency_roles as $role) { + $form[$role] = [ + '#type' => 'details', + '#title' => $roles[$role]?->label(), + '#group' => 'skills', + ]; + } + } + + /** + * Builds the competency. + * + * @param array $form + * The form. + */ + protected function buildCompetency(array &$form) { + $roles = []; + $role_fields = CompetencyField::roleFields($this->definitions); + + foreach ($role_fields as $role => $fields) { + $roles[$role] = [ + 'correct' => 0, + 'total' => 0, + ]; + foreach ($fields as $field_name) { + $roles[$role]['total'] += 1; + if ($this->entity->get($field_name)?->value) { + $roles[$role]['correct'] += 1; + } + $form[$role][$field_name] = &$form[$field_name]; + unset($form[$field_name]); + } + } + + $setting = $this->competencyService->get(); + $default_tab = 'edit-' . str_replace('_', '-', $setting[0]['role']); + foreach ($setting as $index => $r) { + + $role = $r['role']; + if ($roles[$role]['total'] != $roles[$role]['correct']) { + break; + } + + $next = $setting[$index + 1] ?? NULL; + if (is_null($next)) { + break; + } + + $next_role = $next['role']; + $default_tab = 'edit-' . str_replace('_', '-', $next_role); + } + + $form['skills']['#default_tab'] = $default_tab; + } + + /** + * Sets the default tab. + * + * @param array $form + * The form. + */ + private function setDefaultTab(&$form) { + + } + + /** + * {@inheritdoc} + */ + public function save(array $form, FormStateInterface $form_state) { + $contributor_proposal = $form_state->getValue('contributor_proposal'); + $publisher_proposal = $form_state->getValue('publisher_proposal'); + /** @var \Drupal\knowledge\KnowledgeCompetencyInterface $competency */ + $competency = $this->entity; + if (empty($competency->contributor_proposed->value) && $contributor_proposal) { + $competency->contributor_proposed->value = $this->time->getCurrentTime(); + $competency->contributor_coach->target_id = $this->account->id(); + } + elseif (!empty($competency->contributor_proposed->value) && !$contributor_proposal) { + $competency->contributor_proposed->value = NULL; + $competency->contributor_coach->target_id = NULL; + $competency->contributor_leader->target_id = NULL; + } + if (empty($competency->publisher_proposed->value) && $publisher_proposal) { + $competency->publisher_proposed->value = $this->time->getCurrentTime(); + $competency->publisher_coach->target_id = $this->account->id(); + } + elseif (!empty($competency->publisher_proposed->value) && !$publisher_proposal) { + $competency->publisher_proposed->value = NULL; + $competency->publisher_coach->target_id = NULL; + $competency->publisher_leader->target_id = NULL; + } + $roles = $competency->get('roles'); + foreach ($roles as $index => $role) { + + if ($role->proposer) { + $roles[$index]->proposer = $role->proposer->id(); + } + if ($role->approver) { + $roles[$index]->approver = $role->approver->id(); + } + + } + + $status = parent::save($form, $form_state); + + switch ($status) { + case SAVED_NEW: + $this->messenger()->addMessage($this->t("Created %user's Competency.", [ + '%user' => $competency->getOwner()->label(), + ])); + break; + + default: + $this->messenger()->addMessage($this->t("Saved %user's Competency.", [ + '%user' => $competency->getOwner()->label(), + ])); + } + + return $status; + } + +} diff --git a/src/Form/CompetencyRoleForm.php b/src/Form/CompetencyRoleForm.php new file mode 100644 index 0000000000000000000000000000000000000000..ad4f50f3cdbd9380a8d051324d058d9a5eaede4f --- /dev/null +++ b/src/Form/CompetencyRoleForm.php @@ -0,0 +1,278 @@ +<?php + +namespace Drupal\knowledge\Form; + +use Drupal\Component\Serialization\Json; +use Drupal\Core\Config\Config; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Form\FormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\knowledge\KnowledgeCompetencyServiceInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Role for the Competency entity. + * + * @ingroup knowledge + */ +class CompetencyRoleForm extends FormBase { + + /** + * The user role storage. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $roleStorage; + + /** + * The knowledge settings config. + * + * @var \Drupal\Core\Config\Config + */ + protected $settings; + + /** + * The competency service. + * + * @var \Drupal\knowledge\KnowledgeCompetencyServiceInterface + */ + protected $competency; + + /** + * The Competency Role settings. + * + * @param \Drupal\Core\Config\Config $settings + * The settings. + * @param \Drupal\Core\Entity\EntityStorageInterface $role_storage + * The role storage. + * @param \Drupal\knowledge\KnowledgeCompetencyServiceInterface $competency + * The competency service. + */ + public function __construct(Config $settings, EntityStorageInterface $role_storage, KnowledgeCompetencyServiceInterface $competency) { + $this->settings = $settings; + $this->roleStorage = $role_storage; + $this->competency = $competency; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('config.factory')->getEditable('knowledge.competency.settings'), + $container->get('entity_type.manager')->getStorage('user_role'), + $container->get('knowledge.competency'), + ); + } + + /** + * Returns a unique string identifying the form. + * + * @return string + * The unique string identifying the form. + */ + public function getFormId() { + return 'knowledge_competency_role_settings'; + } + + /** + * Defines the settings form for Competency entities. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return array + * Form definition array. + */ + public function buildForm(array $form, FormStateInterface $form_state) { + + $all_roles = $this->getRoles(TRUE); + $competency = $this->competency->get(); + $competency_roles = $this->competency->getRoleIds(); + + $roles = $this->roleStorage->loadMultiple($competency_roles); + $form['roles'] = [ + '#type' => 'select', + '#title' => $this->t('Roles'), + '#options' => $all_roles, + '#multiple' => TRUE, + '#default_value' => $competency_roles, + ]; + + $form['role_weight'] = [ + '#type' => 'table', + '#title' => $this->t('Fields'), + '#header' => [ + $this->t('Role'), + $this->t('Weight'), + $this->t('Action'), + $this->t('Promote'), + ], + '#tabledrag' => [[ + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'draggable-weight', + ], + ], + ]; + $weight_delta = round(count($competency_roles) / 2); + $promote_options = [ + '_none' => $this->t('None'), + '_self' => $this->t('Promote to this role'), + '_next' => $this->t('Promote next role'), + ]; + $promote_options = array_merge($promote_options, $competency_roles); + foreach ($competency as $info) { + $role = $info['role']; + $title = $roles[$role]?->label() ?? $role ?? $this->t('Unknown role'); + $form['role_weight']['#tabledrag'][] = [ + 'action' => 'match', + 'relationship' => 'sibling', + 'group' => 'field-role-select', + 'subgroup' => 'field-role-' . $role, + 'hidden' => FALSE, + ]; + $form['role_weight']['#tabledrag'][] = [ + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'field-weight', + 'subgroup' => 'field-weight-' . $role, + ]; + + $form['role_weight'][$role] = [ + '#attributes' => [ + 'class' => ['role-title', 'role-title-' . $role, 'draggable'], + 'no_striping' => TRUE, + ], + ]; + + $form['role_weight'][$role]['title'] = [ + '#theme_wrappers' => [ + 'container' => [ + '#attributes' => ['class' => 'role-title__action'], + ], + ], + '#prefix' => $title, + '#type' => 'link', + '#title' => $this->t('Place block <span class="visually-hidden">in the %region region</span>', ['%region' => $title]), + '#wrapper_attributes' => [ + // 'colspan' => 5, + ], + '#attributes' => [ + 'class' => ['use-ajax', 'button', 'button--small'], + 'data-dialog-type' => 'modal', + 'data-dialog-options' => Json::encode([ + 'width' => 880, + ]), + ], + ]; + $form['role_weight'][$role]['weight'] = [ + '#type' => 'weight', + '#default_value' => $info['weight'] ?? 0, + '#delta' => $weight_delta, + '#title' => $this->t('Weight for @block block', ['@block' => $title]), + '#title_display' => 'invisible', + '#attributes' => [ + 'class' => ['draggable-weight', 'field-weight', 'field-weight-' . $role], + ], + ]; + + $form['role_weight'][$role]['action'] = [ + '#type' => 'select', + '#options' => [ + '_none' => $this->t('Do nothing'), + 'auto' => $this->t('Promote automatically'), + 'leader' => $this->t('Promote with leadership approval'), + ], + '#default_value' => $info['action'] ?? '_none', + '#title' => $this->t('Action for @field field', ['@field' => $title]), + '#title_display' => 'invisible', + '#parents' => ['role_weight', $role, 'action'], + ]; + + $form['role_weight'][$role]['promote'] = [ + '#type' => 'select', + '#options' => [ + 'self' => $this->t('Promote to this role'), + 'next' => $this->t('Promote next role'), + ], + '#default_value' => $info['promote'] ?? '_none', + '#title' => $this->t('Promote for @field field', ['@field' => $title]), + '#title_display' => 'invisible', + '#parents' => ['role_weight', $role, 'promote'], + '#states' => [ + 'invisible' => [ + ':input[name="role_weight[' . $role . '][action]"]' => ['value' => '_none'], + ], + ], + ]; + } + + $form['actions'] = [ + '#type' => 'actions', + ]; + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Save'), + '#button_type' => 'primary', + '#submit' => ['::submitForm'], + ]; + + return $form; + } + + /** + * Get all roles. + * + * @return array + * The roles. + */ + private function getRoles() { + $roles = []; + foreach ($this->roleStorage->loadMultiple() as $role) { + $roles[$role->id()] = $role->label(); + } + unset($roles['anonymous']); + unset($roles['authenticated']); + unset($roles['administrator']); + unset($roles['knowledge_coach']); + unset($roles['knowledge_leader']); + + return $roles; + } + + /** + * Form submission handler. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + + $roles = []; + $role_weight = $form_state->getValue('role_weight'); + foreach ($form_state->getValue('roles') as $role) { + $weight = isset($role_weight[$role]['weight']) ? (int) $role_weight[$role]['weight'] : 0; + $action = $role_weight[$role]['action'] ?? '_none'; + $promote = $role_weight[$role]['promote'] ?? '_none'; + if ($action === '_none') { + $promote = '_none'; + } + $roles[] = [ + 'role' => $role, + 'weight' => $weight, + 'action' => $action, + 'promote' => $promote, + ]; + } + + $this->settings + ->set('roles', $roles) + ->save(); + } + +} diff --git a/src/Form/CompetencySettingsForm.php b/src/Form/CompetencySettingsForm.php new file mode 100644 index 0000000000000000000000000000000000000000..466a9a32fe000a28b89bd684965f495afcdd554c --- /dev/null +++ b/src/Form/CompetencySettingsForm.php @@ -0,0 +1,317 @@ +<?php + +namespace Drupal\knowledge\Form; + +use Drupal\Component\Serialization\Json; +use Drupal\Component\Utility\Html; +use Drupal\Core\Config\ImmutableConfig; +use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Form\FormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\knowledge\KnowledgeCompetencyServiceInterface; +use Drupal\knowledge_field\Helper\CompetencyField; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Settings for the KnowledgeCompetency entity. + * + * @ingroup knowledge + */ +class CompetencySettingsForm extends FormBase { + + /** + * The user role storage. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $roleStorage; + + /** + * The knowledge settings config. + * + * @var \Drupal\Core\Config\Config + */ + protected $settings; + + /** + * The competency service. + * + * @var \Drupal\knowledge\KnowledgeCompetencyServiceInterface + */ + protected $competencyService; + + /** + * The Competency settings form. + * + * @param \Drupal\Core\Config\ImmutableConfig $settings + * The settings. + * @param \Drupal\Core\Entity\EntityStorageInterface $role_storage + * The role storage. + * @param \Drupal\knowledge\KnowledgeCompetencyServiceInterface $competency_service + * The competency service. + */ + public function __construct(ImmutableConfig $settings, EntityStorageInterface $role_storage, KnowledgeCompetencyServiceInterface $competency_service) { + $this->settings = $settings; + $this->roleStorage = $role_storage; + $this->competencyService = $competency_service; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('config.factory')->get('knowledge.competency.settings'), + $container->get('entity_type.manager')->getStorage('user_role'), + $container->get('knowledge.competency') + ); + } + + /** + * Returns a unique string identifying the form. + * + * @return string + * The unique string identifying the form. + */ + public function getFormId() { + return 'knowledge_competency_settings'; + } + + /** + * Defines the settings form for Competency entities. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return array + * Form definition array. + */ + public function buildForm(array $form, FormStateInterface $form_state) { + + $competency_roles = $this->competencyService->getRoleIds(); + $role_options = []; + $role_options['_none'] = $this->t('No role'); + foreach ($this->roleStorage->loadMultiple($competency_roles) as $role) { + $role_options[$role->id()] = $role->label(); + } + + $fields = []; + $items = $this->getFields(); + $weight_delta = round(count($items) / 2); + + $placement = FALSE; + foreach ($items as $field_id => $field) { + + $fields[$field['role']][$field_id] = [ + 'label' => $field['label'], + 'entity_id' => $field_id, + 'weight' => $field['weight'], + 'entity' => $field, + 'status' => 1, + ]; + } + + $form['fields'] = [ + '#type' => 'table', + '#title' => $this->t('Fields'), + '#header' => [ + $this->t('Field'), + $this->t('Role'), + $this->t('Weight'), + ], + '#tabledrag' => [[ + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'draggable-weight', + ], + ], + '#empty' => $this->t('No items.'), + '#tableselect' => FALSE, + ]; + $weight = 0; + $competency_roles[] = '_none'; + + foreach ($competency_roles as $role) { + + $title = $role_options[$role]; + $form['fields']['#tabledrag'][] = [ + 'action' => 'match', + 'relationship' => 'sibling', + 'group' => 'field-role-select', + 'subgroup' => 'field-role-' . $role, + 'hidden' => FALSE, + ]; + $form['fields']['#tabledrag'][] = [ + 'action' => 'order', + 'relationship' => 'sibling', + 'group' => 'field-weight', + 'subgroup' => 'field-weight-' . $role, + ]; + + $form['fields']['role-' . $role] = [ + '#attributes' => [ + 'class' => ['role-title', 'role-title-' . $role], + 'no_striping' => TRUE, + ], + ]; + $form['fields']['role-' . $role]['title'] = [ + '#theme_wrappers' => [ + 'container' => [ + '#attributes' => ['class' => 'role-title__action'], + ], + ], + '#prefix' => $title, + '#type' => 'link', + '#title' => $this->t('Place block <span class="visually-hidden">in the %region region</span>', ['%region' => $title]), + '#wrapper_attributes' => [ + 'colspan' => 5, + ], + '#attributes' => [ + 'class' => ['use-ajax', 'button', 'button--small'], + 'data-dialog-type' => 'modal', + 'data-dialog-options' => Json::encode([ + 'width' => 880, + ]), + ], + ]; + + $form['fields']['role-' . $role . '-message'] = [ + '#attributes' => [ + 'class' => [ + 'role-message', + 'role-' . $role . '-message', + empty($fields[$role]) ? 'role-empty' : 'role-populated', + ], + ], + ]; + $form['fields']['role-' . $role . '-message']['message'] = [ + '#markup' => '<em>' . $this->t('No competencies in this role') . '</em>', + '#wrapper_attributes' => [ + 'colspan' => 5, + ], + ]; + + if (isset($fields[$role])) { + foreach ($fields[$role] as $info) { + $field_id = $info['entity_id']; + + $form['fields'][$field_id] = [ + '#attributes' => [ + 'class' => ['draggable'], + ], + ]; + $form['fields'][$field_id]['#attributes']['class'][] = $info['status'] ? 'fields-enabled' : 'fields-disabled'; + if ($placement && $placement == Html::getClass($field_id)) { + $form['fields'][$field_id]['#attributes']['class'][] = 'color-success'; + $form['fields'][$field_id]['#attributes']['class'][] = 'js-fields-placed'; + } + $form['fields'][$field_id]['info'] = [ + '#wrapper_attributes' => [ + 'class' => ['field'], + ], + ]; + // Ensure that the label is always rendered as plain text. Render + // array #plain_text key is essentially treated same as @ placeholder + // in translatable markup. + if ($info['status']) { + $form['fields'][$field_id]['info']['#plain_text'] = $info['label']; + } + else { + $form['fields'][$field_id]['info']['#markup'] = $this->t('@label (disabled)', ['@label' => $info['label']]); + } + + $form['fields'][$field_id]['role-theme']['role'] = [ + '#type' => 'select', + '#default_value' => $role, + '#required' => TRUE, + '#title' => $this->t('Role for @field field', ['@field' => $info['label']]), + '#title_display' => 'invisible', + '#options' => $role_options, + '#attributes' => [ + 'class' => ['field-role-select', 'field-role-' . $role], + ], + '#parents' => ['fields', $field_id, 'role'], + ]; + + $form['fields'][$field_id]['weight'] = [ + '#type' => 'weight', + '#default_value' => $info['weight'], + '#delta' => $weight_delta, + '#title' => $this->t('Weight for @block block', ['@block' => $info['label']]), + '#title_display' => 'invisible', + '#attributes' => [ + 'class' => ['draggable-weight', 'field-weight', 'field-weight-' . $role], + ], + ]; + + } + } + } + + $form['actions'] = [ + '#type' => 'actions', + ]; + $form['actions']['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Save'), + '#button_type' => 'primary', + '#submit' => ['::submitForm'], + ]; + + $form['#attached']['library'][] = 'core/drupal.tableheader'; + $form['#attached']['library'][] = 'knowledge/competency.admin'; + + return $form; + } + + /** + * Form submission handler. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + // Empty implementation of the abstract submit class. + $fields = $form_state->getValue('fields'); + + $fields_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('knowledge_competency', 'knowledge_competency'); + foreach ($fields as $field_id => $field) { + $role = $field['role']; + $fields_definitions[$field_id]->setThirdPartySetting('knowledge', 'competency_role', $role); + $fields_definitions[$field_id]->save(); + } + + } + + /** + * Get all fields. + */ + protected function getFields() { + $form = \Drupal::service('entity_display.repository')->getFormDisplay('knowledge_competency', 'knowledge_competency', 'default'); + + $fields_definitions = $form->get('fieldDefinitions'); + $content = $form->get('content'); + $fields = []; + $role_fields = CompetencyField::roleFields($fields_definitions); + foreach ($role_fields as $role => $field_names) { + foreach ($field_names as $field_name) { + if (!array_key_exists($field_name, $content)) { + continue; + } + + $fields[$field_name] = [ + 'label' => $fields_definitions[$field_name]->getLabel(), + 'weight' => $content[$field_name]['weight'], + 'role' => $role, + ]; + } + } + + return $fields; + } + +} diff --git a/src/Form/GovernanceForm.php b/src/Form/GovernanceForm.php index e139dd205bda2d78894e8e7a40ba333fec687f6d..f0c9cbd425487ff2333a1119e85207559ba78280 100644 --- a/src/Form/GovernanceForm.php +++ b/src/Form/GovernanceForm.php @@ -66,7 +66,11 @@ final class GovernanceForm extends ConfigFormBase { $settings = $this->config('knowledge.governance.settings'); $roles = $this->roleStorage->loadMultiple(); $options = []; + $skip_roles = ['anonymous', 'authenticated']; foreach ($roles as $machine_name => $role) { + if (in_array($machine_name, $skip_roles)) { + continue; + } $options[$machine_name] = $role->label(); } $form['roles'] = [ diff --git a/src/Form/KnowledgeCompetencyApproveForm.php b/src/Form/KnowledgeCompetencyApproveForm.php deleted file mode 100644 index fadaf9a9bc7e9c2a05d0b08ed1bd22d59ee1bb5e..0000000000000000000000000000000000000000 --- a/src/Form/KnowledgeCompetencyApproveForm.php +++ /dev/null @@ -1,199 +0,0 @@ -<?php - -namespace Drupal\knowledge\Form; - -use Drupal\Core\Form\ConfirmFormBase; -use Drupal\Core\Form\FormStateInterface; -use Drupal\user\Entity\Role; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** - * Provides the knowledge delete confirmation form. - * - * @internal - */ -class KnowledgeCompetencyApproveForm extends ConfirmFormBase { - - /** - * The knowledge competency. - * - * @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface - */ - protected $competency; - - /** - * The user to be promoted. - * - * @var \Drupal\user\UserInterface - */ - protected $learner; - - /** - * The role to ne promoted to. - * - * @var \Drupal\user\RoleInterface - */ - protected $role; - - /** - * The current user account. - * - * @var \Drupal\Core\Session\AccountProxyInterface - */ - protected $account; - - /** - * The time service. - * - * @var \Drupal\Component\Datetime\TimeInterface - */ - protected $time; - - /** - * The competency storage service. - * - * @var \Drupal\Core\Entity\EntityStorageInterface - */ - protected $competencyStorage; - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - // Instantiates this form class. - $instance = parent::create($container); - $instance->account = $container->get('current_user'); - $instance->time = $container->get('datetime.time'); - $instance->competencyStorage = $container->get('entity_type.manager') - ->getStorage('knowledge_competency'); - return $instance; - } - - /** - * {@inheritdoc} - */ - public function getFormId() : string { - return "confirm_knowledge_competency_approve_form"; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, FormStateInterface $form_state, $user = '') { - $competency = $this->getCompetency($user); - $this->setCompetency($competency); - $form = parent::buildForm($form, $form_state); - - return $form; - } - - /** - * Get the user's competency. - */ - protected function getCompetency($user) { - $query = $this->competencyStorage->getQuery(); - $result = $query - ->condition('user_id', $user) - ->accessCheck(FALSE) - ->execute(); - $competency = NULL; - if (count($result) == 1) { - $competency = $this->competencyStorage->load(current($result)); - } - if (count($result) == 0) { - $competency = $this->competencyStorage->create([ - 'user_id' => $user, - ]); - } - - return $competency; - } - - /** - * {@inheritdoc} - */ - public function getConfirmText() { - return $this->t('Promote'); - } - - /** - * {@inheritdoc} - */ - public function getCancelUrl() { - // Point to the entity of which this knowledge is a reply. - return $this->competency->toUrl(); - } - - /** - * {@inheritdoc} - */ - protected function getRedirectUrl() { - return $this->getCancelUrl(); - } - - /** - * {@inheritdoc} - */ - public function getDescription() { - return $this->t('Do you want to promote the user?'); - } - - /** - * {@inheritdoc} - */ - public function getQuestion() { - $username = $this->learner ? $this->learner->label() : '<unknown>'; - $role = $this->role ? $this->role->label() : '<unknown>'; - $p = [ - '@username' => $username, - '@role' => $role, - ]; - return $this->t('Do you want to promote @username to a @role?', $p); - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, FormStateInterface $form_state) { - $competency = $this->competency; - $learner = $this->learner; - $role = $this->role->id(); - - if ($learner->hasRole('knowledge_candidate')) { - $learner->removeRole('knowledge_candidate'); - } - if ($role == 'knowledge_publisher' && $learner->hasRole('knowledge_contributor')) { - $learner->removeRole('knowledge_contributor'); - } - - $learner->addRole($role); - $learner->save(); - if ($competency->isPendingPublisher()) { - $competency->publisher_approved->value = $this->time->getCurrentTime(); - $competency->publisher_leader->target_id = $this->account->id(); - } - elseif ($competency->isPendingContributor()) { - $competency->contributor_approved->value = $this->time->getCurrentTime(); - $competency->contributor_leader->target_id = $this->account->id(); - } - $competency->save(); - - $form_state->setRedirect('entity.knowledge_competency.canonical', ['knowledge_competency' => $this->competency->id()]); - } - - /** - * Sets the competency pending approval. - */ - public function setCompetency($competency) { - $this->competency = $competency; - $this->learner = $competency->getOwner(); - if ($competency->isPendingContributor()) { - $this->role = Role::load('knowledge_contributor'); - } - elseif ($competency->isPendingPublisher()) { - $this->role = Role::load('knowledge_publisher'); - } - - } - -} diff --git a/src/Form/KnowledgeCompetencyDeleteForm.php b/src/Form/KnowledgeCompetencyDeleteForm.php deleted file mode 100644 index ba9852e5d78aa48b00252feb67f0769d16432b20..0000000000000000000000000000000000000000 --- a/src/Form/KnowledgeCompetencyDeleteForm.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php - -namespace Drupal\knowledge\Form; - -use Drupal\Core\Entity\ContentEntityDeleteForm; - -/** - * Provides a form for deleting Competency entities. - * - * @ingroup knowledge - */ -class KnowledgeCompetencyDeleteForm extends ContentEntityDeleteForm { - - -} diff --git a/src/Form/KnowledgeCompetencyForm.php b/src/Form/KnowledgeCompetencyForm.php deleted file mode 100644 index f120760cc7080e97fe3268ece2136f11b23f38b0..0000000000000000000000000000000000000000 --- a/src/Form/KnowledgeCompetencyForm.php +++ /dev/null @@ -1,349 +0,0 @@ -<?php - -namespace Drupal\knowledge\Form; - -use Drupal\Core\Entity\ContentEntityForm; -use Drupal\Core\Form\FormStateInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** - * Form controller for Competency edit forms. - * - * @ingroup knowledge - */ -class KnowledgeCompetencyForm extends ContentEntityForm { - - /** - * The current user account. - * - * @var \Drupal\Core\Session\AccountProxyInterface - */ - protected $account; - - /** - * The knowledge settings config. - * - * @var \Drupal\Core\Config\Config - */ - protected $config; - - /** - * The database connection. - * - * @var \Drupal\Core\Database\Connection - */ - protected $database; - - /** - * The date formatter service. - * - * @var \Drupal\Core\Datetime\DateFormatter - */ - protected $dateFormatter; - - /** - * The user role storage service. - * - * @var \Drupal\Core\Entity\EntityStorageInterface - */ - protected $roleStorage; - - /** - * The field group info array. - * - * @var array - */ - protected $groups; - - /** - * The Renderer service. - * - * @var \Drupal\Core\Render\Renderer - */ - protected $render; - - /** - * The block manager service. - * - * @var \Drupal\Core\Block\BlockManagerInterface - */ - protected $blockManager; - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - // Instantiates this form class. - $instance = parent::create($container); - $instance->account = $container->get('current_user'); - $instance->roleStorage = $container->get('entity_type.manager')->getStorage('user_role'); - $instance->config = $container->get('config.factory')->get('knowledge.settings'); - $instance->dateFormatter = $container->get('date.formatter'); - $instance->time = $container->get('datetime.time'); - $instance->groups = field_group_info_groups('knowledge_competency', 'knowledge_competency', 'form', 'default'); - $instance->render = $container->get('renderer'); - $instance->blockManager = $container->get('plugin.manager.block'); - return $instance; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, FormStateInterface $form_state) { - $form = parent::buildForm($form, $form_state); - // In several places within this function, we vary $form on: - // - The current user's permissions. - // - Whether the current user is authenticated or anonymous. - // - The 'user.settings' configuration. - // - The knowledge field's definition. - $form['#cache']['contexts'][] = 'user'; - $form['#cache']['contexts'][] = 'user.roles:authenticated'; - - unset($form['revision_information']); - unset($form['revision']); - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $competency */ - $competency = $this->entity; - $user = $competency->getOwner(); - $roles = $user->getRoles(); - - $is_publisher = in_array('knowledge_publisher', $roles); - $is_contributor = in_array('knowledge_contributor', $roles) && !$is_publisher; - $is_candidate = in_array('knowledge_candidate', $roles) && !$is_contributor && !$is_publisher; - - if (!($is_candidate || $is_contributor || $is_publisher)) { - return ['#markup' => $this->t('@username is not a knowledge worker.', ['@username' => $user->toLink()->toString()])]; - } - - $form['user_id']['#type'] = 'hidden'; - - $candidate_option = $this->config->get('competency.candidate'); - $has_candidate_option = $candidate_option != '_none'; - $contributor_option = $this->config->get('competency.contributor'); - $has_contributor_option = $contributor_option != '_none'; - $publisher_option = $this->config->get('competency.publisher'); - $has_publisher_option = $publisher_option != '_none'; - $all_option = $this->config->get('competency.all'); - $has_all_option = $all_option != '_none'; - - if ($has_candidate_option) { - if ($candidate_option == 'contributor' && $is_candidate) { - $this->addPromoteContributorField($form); - $this->addCandidateChecks($form, $candidate_option); - } - elseif ($candidate_option == 'publisher' && $is_contributor) { - $this->addPromotePublisherField($form); - $this->addCandidateChecks($form, $candidate_option); - } - } - - if ($has_contributor_option) { - if ($contributor_option == 'contributor' && $is_candidate) { - $this->addPromoteContributorField($form); - $this->addContributorChecks($form, $contributor_option); - } - elseif ($contributor_option == 'publisher' && $is_contributor) { - $this->addPromotePublisherField($form); - $this->addContributorChecks($form, $contributor_option); - } - } - - if ($has_publisher_option) { - if ($publisher_option == 'contributor' && $is_candidate) { - $this->addPromoteContributorField($form); - $this->addPublisherChecks($form, $publisher_option); - } - elseif ($publisher_option == 'publisher' && $is_contributor) { - $this->addPromotePublisherField($form); - $this->addPublisherChecks($form, $publisher_option); - } - } - - if ($has_all_option) { - if ($all_option == 'contributor' && $is_candidate) { - $this->addPromoteContributorField($form); - $this->addAllChecks($form, $all_option); - } - elseif ($all_option == 'publisher' && $is_contributor) { - $this->addPromotePublisherField($form); - $this->addAllChecks($form, $all_option); - } - } - - $form['#attached']['library'][] = 'knowledge/competency_form'; - - return $form; - } - - /** - * Renders a block plugin as markup. - */ - protected function renderPluginBlock($plugin_id, $config = []) { - $plugin_block = $this->blockManager->createInstance($plugin_id, $config); - // Some blocks might implement access check. - $access_result = $plugin_block->access($this->account); - - // Return empty render array if user doesn't have access. - // $access_result can be boolean or an AccessResult class. - if (is_object($access_result) - && $access_result->isForbidden() - || is_bool($access_result) && !$access_result) { - return []; - } - - $render = $plugin_block->build(); - - $this->render->addCacheableDependency($render, $plugin_block); - - return $render; - } - - /** - * {@inheritdoc} - */ - public function save(array $form, FormStateInterface $form_state) { - $contributor_proposal = $form_state->getValue('contributor_proposal'); - $publisher_proposal = $form_state->getValue('publisher_proposal'); - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $competency */ - $competency = $this->entity; - if (empty($competency->contributor_proposed->value) && $contributor_proposal) { - $competency->contributor_proposed->value = $this->time->getCurrentTime(); - $competency->contributor_coach->target_id = $this->account->id(); - } - elseif (!empty($competency->contributor_proposed->value) && !$contributor_proposal) { - $competency->contributor_proposed->value = NULL; - $competency->contributor_coach->target_id = NULL; - $competency->contributor_leader->target_id = NULL; - } - if (empty($competency->publisher_proposed->value) && $publisher_proposal) { - $competency->publisher_proposed->value = $this->time->getCurrentTime(); - $competency->publisher_coach->target_id = $this->account->id(); - } - elseif (!empty($competency->publisher_proposed->value) && !$publisher_proposal) { - $competency->publisher_proposed->value = NULL; - $competency->publisher_coach->target_id = NULL; - $competency->publisher_leader->target_id = NULL; - } - $status = parent::save($form, $form_state); - - switch ($status) { - case SAVED_NEW: - $this->messenger()->addMessage($this->t('Created the %label Competency.', [ - '%label' => $competency->label(), - ])); - break; - - default: - $this->messenger()->addMessage($this->t('Saved the %label Competency.', [ - '%label' => $competency->label(), - ])); - } - - return $status; - } - - /** - * Adds the contributor proposal field. - */ - protected function addPromoteContributorField(array &$form) { - $contributor = $this->roleStorage->load('knowledge_contributor'); - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $competency */ - $competency = $this->entity; - $is_proposed = !empty($competency->contributor_proposed->value); - if ($is_proposed) { - $contributor_coach = $competency->contributor_coach->entity->label(); - $date = $this->dateFormatter->format($competency->contributor_proposed->value, 'long'); - $description = $this->t('@username proposed on @date', [ - '@username' => $contributor_coach, - '@date' => $date, - ]); - } - else { - $description = $this->t('Propose user be promoted to a @contributor.', - [ - '@contributor' => $contributor->label(), - ]); - } - $form['contributor_proposal'] = [ - '#type' => 'checkbox', - '#title' => $contributor->label(), - '#description' => $description, - '#group' => 'second', - '#default_value' => $is_proposed, - '#weight' => 0, - ]; - } - - /** - * Adds the publisher proposal field. - */ - protected function addPromotePublisherField(array &$form) { - $publisher = $this->roleStorage->load('knowledge_publisher'); - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $competency */ - $competency = $this->entity; - $is_proposed = !empty($competency->publisher_proposed->value); - if ($is_proposed) { - $publisher_coach = $competency->publisher_coach->entity->label(); - $date = $this->dateFormatter->format($competency->publisher_proposed->value, 'long'); - $description = $this->t('@username proposed on @date', [ - '@username' => $publisher_coach, - '@date' => $date, - ]); - } - else { - $description = $this->t('Propose user be promoted to a @publisher.', - [ - '@publisher' => $publisher->label(), - ]); - } - $form['publisher_proposal'] = [ - '#type' => 'checkbox', - '#title' => $publisher->label(), - '#description' => $description, - '#group' => 'second', - '#default_value' => $is_proposed, - ]; - - } - - /** - * Adds state checks to a field based on a role. - */ - protected function addChecks(array &$form, string $role_name, string $group_name) { - foreach ($this->groups[$group_name]->children as $field_name) { - $form[$role_name . '_proposal']['#states']['visible'][':input[name="' . $field_name . '[value]"]'] = [ - 'checked' => TRUE, - ]; - } - } - - /** - * Adds candidate state checks to a field. - */ - protected function addCandidateChecks(array &$form, string $role_name) { - $this->addChecks($form, $role_name, 'group_candidate'); - } - - /** - * Adds contributor state checks to a field. - */ - protected function addContributorChecks(array &$form, string $role_name) { - $this->addChecks($form, $role_name, 'group_contributor'); - } - - /** - * Adds publisher state checks to a field. - */ - protected function addPublisherChecks(array &$form, string $role_name) { - $this->addChecks($form, $role_name, 'group_publisher'); - } - - /** - * Adds all state checks to a field. - */ - protected function addAllChecks(array &$form, string $role_name) { - $this->addCandidateChecks($form, $role_name); - $this->addContributorChecks($form, $role_name); - $this->addPublisherChecks($form, $role_name); - } - -} diff --git a/src/Form/KnowledgeCompetencyRevisionDeleteForm.php b/src/Form/KnowledgeCompetencyRevisionDeleteForm.php index f241044c105567e189db17c437057beb28df0a0f..e72d3e5042e643f94d1c4ec4fca89edb4ce03c86 100644 --- a/src/Form/KnowledgeCompetencyRevisionDeleteForm.php +++ b/src/Form/KnowledgeCompetencyRevisionDeleteForm.php @@ -25,7 +25,7 @@ class KnowledgeCompetencyRevisionDeleteForm extends ConfirmFormBase { /** * The Competency revision. * - * @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface + * @var \Drupal\knowledge\KnowledgeCompetencyInterface */ protected $revision; diff --git a/src/Form/KnowledgeCompetencyRevisionRevertForm.php b/src/Form/KnowledgeCompetencyRevisionRevertForm.php index e4dc79100100457ea40608810da80fb04499e6ff..a500821267e1dc2d39d7364fc61a9dad0fe9ff1f 100644 --- a/src/Form/KnowledgeCompetencyRevisionRevertForm.php +++ b/src/Form/KnowledgeCompetencyRevisionRevertForm.php @@ -5,7 +5,7 @@ namespace Drupal\knowledge\Form; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; -use Drupal\knowledge\Entity\KnowledgeCompetencyInterface; +use Drupal\knowledge\KnowledgeCompetencyInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -18,7 +18,7 @@ class KnowledgeCompetencyRevisionRevertForm extends ConfirmFormBase { /** * The Competency revision. * - * @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface + * @var \Drupal\knowledge\KnowledgeCompetencyInterface */ protected $revision; @@ -132,12 +132,12 @@ class KnowledgeCompetencyRevisionRevertForm extends ConfirmFormBase { /** * Prepares a revision to be reverted. * - * @param \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $revision + * @param \Drupal\knowledge\KnowledgeCompetencyInterface $revision * The revision to be reverted. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. * - * @return \Drupal\knowledge\Entity\KnowledgeCompetencyInterface + * @return \Drupal\knowledge\KnowledgeCompetencyInterface * The prepared revision ready to be stored. */ protected function prepareRevertedRevision(KnowledgeCompetencyInterface $revision, FormStateInterface $form_state) { diff --git a/src/Form/KnowledgeCompetencySettingsForm.php b/src/Form/KnowledgeCompetencySettingsForm.php deleted file mode 100644 index a23ff43ce0d27900d61a01861a731272f57f4ed3..0000000000000000000000000000000000000000 --- a/src/Form/KnowledgeCompetencySettingsForm.php +++ /dev/null @@ -1,133 +0,0 @@ -<?php - -namespace Drupal\knowledge\Form; - -use Drupal\Core\Form\FormBase; -use Drupal\Core\Form\FormStateInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** - * Settings for the KnowledgeCompetency entity. - * - * @ingroup knowledge - */ -class KnowledgeCompetencySettingsForm extends FormBase { - - /** - * The user role storage. - * - * @var \Drupal\Core\Entity\EntityStorageInterface - */ - protected $roleStorage; - - /** - * The knowledge settings config. - * - * @var \Drupal\Core\Config\Config - */ - protected $config; - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - // Instantiates this form class. - $instance = parent::create($container); - $instance->roleStorage = $container->get('entity_type.manager')->getStorage('user_role'); - $instance->config = $container->get('config.factory')->getEditable('knowledge.settings'); - return $instance; - } - - /** - * Returns a unique string identifying the form. - * - * @return string - * The unique string identifying the form. - */ - public function getFormId() { - return 'knowledge_competency_settings'; - } - - /** - * Form submission handler. - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. - */ - public function submitForm(array &$form, FormStateInterface $form_state) { - // Empty implementation of the abstract submit class. - $this->config - ->set('competency.candidate', $form_state->getValue('candidate')) - ->set('competency.contributor', $form_state->getValue('contributor')) - ->set('competency.publisher', $form_state->getValue('publisher')) - ->set('competency.all', $form_state->getValue('all')) - ->save(); - } - - /** - * Defines the settings form for Competency entities. - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. - * - * @return array - * Form definition array. - */ - public function buildForm(array $form, FormStateInterface $form_state) { - $candidate = $this->roleStorage->load('knowledge_candidate'); - $contributor = $this->roleStorage->load('knowledge_contributor'); - $publisher = $this->roleStorage->load('knowledge_publisher'); - $options = [ - '_none' => $this->t('Do nothing'), - 'contributor' => $this->t('Promote to @contributor', [ - '@contributor' => $contributor->label(), - ]), - 'publisher' => $this->t('Promote to @publisher', [ - '@publisher' => $publisher->label(), - ]), - ]; - $form['candidate'] = [ - '#title' => $candidate->label(), - '#type' => 'select', - '#options' => $options, - '#default_value' => $this->config->get('competency.candidate'), - ]; - $form['contributor'] = [ - '#title' => $contributor->label(), - '#type' => 'select', - '#options' => $options, - '#default_value' => $this->config->get('competency.contributor'), - ]; - - $form['publisher'] = [ - '#title' => $publisher->label(), - '#type' => 'select', - '#options' => $options, - '#default_value' => $this->config->get('competency.publisher'), - ]; - - $form['all'] = [ - '#title' => $this->t('All'), - '#type' => 'select', - '#options' => $options, - '#default_value' => $this->config->get('competency.all'), - ]; - - $form['actions'] = [ - '#type' => 'actions', - ]; - $form['actions']['submit'] = [ - '#type' => 'submit', - '#value' => $this->t('Save'), - '#button_type' => 'primary', - '#submit' => ['::submitForm'], - ]; - - return $form; - } - -} diff --git a/src/Form/MergeNodeForm.php b/src/Form/MergeNodeForm.php index d2523338dc9a850204d8c591cf7c36ec052ebac0..1cad43091d1a03dd443cb1cd1b29cc2bb3328c45 100644 --- a/src/Form/MergeNodeForm.php +++ b/src/Form/MergeNodeForm.php @@ -47,7 +47,7 @@ class MergeNodeForm extends FormBase { /** * {@inheritdoc} */ - public function buildForm(array $form, FormStateInterface $form_state, NodeInterface $original = NULL, NodeInterface $duplicate = NULL) { + public function buildForm(array $form, FormStateInterface $form_state, ?NodeInterface $original = NULL, ?NodeInterface $duplicate = NULL) { $form_state->set('original_node', $original); $form_state->set('duplicate_node', $duplicate); diff --git a/src/KnowledgeAccessControlHandler.php b/src/KnowledgeAccessControlHandler.php index f0c593660f2bec305760d931aa3c9b19cb2a70b2..60aa0af25fcce9392f83fffd1ac033a7dafb1cd2 100644 --- a/src/KnowledgeAccessControlHandler.php +++ b/src/KnowledgeAccessControlHandler.php @@ -68,7 +68,7 @@ class KnowledgeAccessControlHandler extends EntityAccessControlHandler { /** * {@inheritdoc} */ - protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) { + protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, ?FieldItemListInterface $items = NULL) { if ($operation == 'edit') { // Only users with the "administer knowledge" permission can edit // administrative fields. diff --git a/src/KnowledgeCompetencyAccessControlHandler.php b/src/KnowledgeCompetencyAccessControlHandler.php deleted file mode 100644 index 8a9e1dd7228a6638540bf24dbf87cc363c1880c6..0000000000000000000000000000000000000000 --- a/src/KnowledgeCompetencyAccessControlHandler.php +++ /dev/null @@ -1,53 +0,0 @@ -<?php - -namespace Drupal\knowledge; - -use Drupal\Core\Access\AccessResult; -use Drupal\Core\Entity\EntityAccessControlHandler; -use Drupal\Core\Entity\EntityInterface; -use Drupal\Core\Session\AccountInterface; - -/** - * Access controller for the Competency entity. - * - * @see \Drupal\knowledge\Entity\KnowledgeCompetency. - */ -class KnowledgeCompetencyAccessControlHandler extends EntityAccessControlHandler { - - /** - * {@inheritdoc} - */ - protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $entity */ - - switch ($operation) { - - case 'view': - - if (!$entity->isPublished()) { - return AccessResult::allowedIfHasPermission($account, 'view unpublished competency entities'); - } - - return AccessResult::allowedIfHasPermission($account, 'view published competency entities'); - - case 'update': - - return AccessResult::allowedIfHasPermission($account, 'edit competency entities'); - - case 'delete': - - return AccessResult::allowedIfHasPermission($account, 'delete competency entities'); - } - - // Unknown operation, no opinion. - return AccessResult::neutral(); - } - - /** - * {@inheritdoc} - */ - protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { - return AccessResult::allowedIfHasPermission($account, 'add competency entities'); - } - -} diff --git a/src/Entity/KnowledgeCompetencyInterface.php b/src/KnowledgeCompetencyInterface.php similarity index 79% rename from src/Entity/KnowledgeCompetencyInterface.php rename to src/KnowledgeCompetencyInterface.php index 05fb086c47e850d02e06d6b75418c0d7665d5009..3b9389420dc659593dd2807d898832cdac127c7e 100644 --- a/src/Entity/KnowledgeCompetencyInterface.php +++ b/src/KnowledgeCompetencyInterface.php @@ -1,6 +1,6 @@ <?php -namespace Drupal\knowledge\Entity; +namespace Drupal\knowledge; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityChangedInterface; @@ -32,7 +32,7 @@ interface KnowledgeCompetencyInterface extends ContentEntityInterface, RevisionL * @param int $timestamp * The Competency creation timestamp. * - * @return \Drupal\knowledge\Entity\KnowledgeCompetencyInterface + * @return \Drupal\knowledge\KnowledgeCompetencyInterface * The called Competency entity. */ public function setCreatedTime($timestamp); @@ -51,7 +51,7 @@ interface KnowledgeCompetencyInterface extends ContentEntityInterface, RevisionL * @param int $timestamp * The UNIX timestamp of when this revision was created. * - * @return \Drupal\knowledge\Entity\KnowledgeCompetencyInterface + * @return \Drupal\knowledge\KnowledgeCompetencyInterface * The called Competency entity. */ public function setRevisionCreationTime($timestamp); @@ -70,23 +70,16 @@ interface KnowledgeCompetencyInterface extends ContentEntityInterface, RevisionL * @param int $uid * The user ID of the revision author. * - * @return \Drupal\knowledge\Entity\KnowledgeCompetencyInterface + * @return \Drupal\knowledge\KnowledgeCompetencyInterface * The called Competency entity. */ public function setRevisionUserId($uid); - /** - * Is the competency pending approval for knowledge_contributor. - */ - public function isPendingContributor(); - - /** - * Is the competency pending approval for knowledge_publisher. - */ - public function isPendingPublisher(); - /** * Is the competency pending approval. + * + * @return string|bool + * The role id if the competency is pending approval. */ public function isPending(); diff --git a/src/KnowledgeCompetencyServiceInterface.php b/src/KnowledgeCompetencyServiceInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..70151afca16840d17ed54239834b9431874b7b75 --- /dev/null +++ b/src/KnowledgeCompetencyServiceInterface.php @@ -0,0 +1,82 @@ +<?php + +namespace Drupal\knowledge; + +use Drupal\user\UserInterface; + +/** + * Interface for the Knowledge Competency service. + */ +interface KnowledgeCompetencyServiceInterface { + + /** + * Get the roles. + * + * @return array + * The roles. + */ + public function get(); + + /** + * Get the role ids. + * + * @return array + * The role ids. + */ + public function getRoleIds(); + + /** + * Check if the user has the role or better. + * + * @param string $role + * The role. + * @param array $user_roles + * The user roles. + * + * @return bool + * TRUE if the user has the role or better, FALSE otherwise. + */ + public function hasRoleOrBetter($role, $user_roles); + + /** + * Remove lesser competency roles. + * + * @param \Drupal\user\UserInterface $user + * The user. + */ + public function doRoleRemoval(UserInterface &$user); + + /** + * Calculate values to be saved. + * + * @param array $roles + * The roles. + * @param array $orginal_roles + * The original roles. + */ + public function doPreSave(&$roles, $orginal_roles); + + /** + * Perform actions if any after saving. + * + * @param \Drupal\user\UserInterface $user + * The user. + * @param array $roles + * The roles. + * @param array $orginal_roles + * The original roles. + */ + public function doPostSave($user, $roles, $orginal_roles); + + /** + * Get the user competency. + * + * @param int $user_id + * The user. + * + * @return array + * The user competency. + */ + public function getUserCompetency($user_id); + +} diff --git a/src/KnowledgeCompetencyStorage.php b/src/KnowledgeCompetencyStorage.php index 4571a51a75a58a240babf3e39027f2a78d4116a0..3b284428b0e183cfca72a78ba0a3e48cfcdb9516 100644 --- a/src/KnowledgeCompetencyStorage.php +++ b/src/KnowledgeCompetencyStorage.php @@ -2,9 +2,16 @@ namespace Drupal\knowledge; +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Cache\MemoryCache\MemoryCacheInterface; +use Drupal\Core\Database\Connection; +use Drupal\Core\Entity\EntityFieldManagerInterface; +use Drupal\Core\Entity\EntityTypeBundleInfoInterface; +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\Sql\SqlContentEntityStorage; +use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\knowledge\Entity\KnowledgeCompetencyInterface; /** * Defines the storage handler class for Competency entities. @@ -16,6 +23,32 @@ use Drupal\knowledge\Entity\KnowledgeCompetencyInterface; */ class KnowledgeCompetencyStorage extends SqlContentEntityStorage implements KnowledgeCompetencyStorageInterface { + /** + * Constructs a SqlContentEntityStorage object. + * + * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type + * The entity type definition. + * @param \Drupal\Core\Database\Connection $database + * The database connection to be used. + * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager + * The entity field manager. + * @param \Drupal\Core\Cache\CacheBackendInterface $cache + * The cache backend to be used. + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager + * The language manager. + * @param \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface $memory_cache + * The memory cache backend to be used. + * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info + * The entity type bundle info. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + */ + public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityFieldManagerInterface $entity_field_manager, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, MemoryCacheInterface $memory_cache, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityTypeManagerInterface $entity_type_manager) { + parent::__construct($entity_type, $database, $entity_field_manager, $cache, $language_manager, $memory_cache, $entity_type_bundle_info, $entity_type_manager); + @trigger_error(__NAMESPACE__ . '\KnowledgeCompetencyStorage is deprecated in knowledge:8.x-1.4 and is removed from knowledge:2.0.0. Use \Drupal\knowledge\CompetencyStorage instead. See https://www.drupal.org/node/3476470', E_USER_DEPRECATED); + + } + /** * {@inheritdoc} */ diff --git a/src/KnowledgeCompetencyStorageInterface.php b/src/KnowledgeCompetencyStorageInterface.php index fcc3be2486a584bab8789835dc47a14b70ffdddf..a20547bb8e206f609a271cf8f6d924f4172af5d9 100644 --- a/src/KnowledgeCompetencyStorageInterface.php +++ b/src/KnowledgeCompetencyStorageInterface.php @@ -4,7 +4,6 @@ namespace Drupal\knowledge; use Drupal\Core\Entity\RevisionableStorageInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\knowledge\Entity\KnowledgeCompetencyInterface; /** * Defines the storage handler class for Competency entities. @@ -19,7 +18,7 @@ interface KnowledgeCompetencyStorageInterface extends RevisionableStorageInterfa /** * Gets a list of Competency revision IDs for a specific Competency. * - * @param \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $entity + * @param \Drupal\knowledge\KnowledgeCompetencyInterface $entity * The Competency entity. * * @return int[] diff --git a/src/KnowledgeFieldItemList.php b/src/KnowledgeFieldItemList.php index 104a4c47d50324611f3030d436148f3254d664d8..fd57d790588b07e8181f3771acbd87b30db1e7e6 100644 --- a/src/KnowledgeFieldItemList.php +++ b/src/KnowledgeFieldItemList.php @@ -43,7 +43,7 @@ class KnowledgeFieldItemList extends FieldItemList { /** * {@inheritdoc} */ - public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) { + public function access($operation = 'view', ?AccountInterface $account = NULL, $return_as_object = FALSE) { if ($operation === 'edit') { // Only users with administer knowledge permission can edit the knowledge // status field. diff --git a/src/KnowledgeForm.php b/src/KnowledgeForm.php index dd40909c89a0c3e25f5a3ddef37afd1e4afb5f28..01d905399b0d10c9c6d69375c4a1ee7ec37c58d3 100644 --- a/src/KnowledgeForm.php +++ b/src/KnowledgeForm.php @@ -75,7 +75,7 @@ class KnowledgeForm extends ContentEntityForm { * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * The entity field manager service. */ - public function __construct(EntityRepositoryInterface $entity_repository, AccountInterface $current_user, RendererInterface $renderer, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL, EntityFieldManagerInterface $entity_field_manager = NULL) { + public function __construct(EntityRepositoryInterface $entity_repository, AccountInterface $current_user, RendererInterface $renderer, ?EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, ?TimeInterface $time = NULL, ?EntityFieldManagerInterface $entity_field_manager = NULL) { parent::__construct($entity_repository, $entity_type_bundle_info, $time); $this->currentUser = $current_user; $this->renderer = $renderer; diff --git a/src/KnowledgeStatistics.php b/src/KnowledgeStatistics.php index b6059f411bf6f2231eaa1128aefd0b0825aebee1..82ae466f7ae9bf62d0219349df134ee3479f5783 100644 --- a/src/KnowledgeStatistics.php +++ b/src/KnowledgeStatistics.php @@ -145,7 +145,7 @@ class KnowledgeStatistics implements KnowledgeStatisticsInterface { ModuleHandlerInterface $module_handler, ConfigFactoryInterface $config_factory, MessengerInterface $messenger, - Connection $database_replica = NULL, + ?Connection $database_replica = NULL, ?ContentEntityTrackingManager $tracking_manager = NULL, ) { $this->database = $database; diff --git a/src/KnowledgeTranslationHandler.php b/src/KnowledgeTranslationHandler.php index a31984c9a9366c0ea9d2e3459a36a3b3461d09dc..1bfb6f14756dfdf4014c54b9257a45f35cee66cf 100644 --- a/src/KnowledgeTranslationHandler.php +++ b/src/KnowledgeTranslationHandler.php @@ -2,9 +2,9 @@ namespace Drupal\knowledge; -use Drupal\content_translation\ContentTranslationHandler; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\content_translation\ContentTranslationHandler; /** * Defines the translation handler for knowledge. diff --git a/src/Plugin/Action/ChangeUserWave.php b/src/Plugin/Action/ChangeUserWave.php index 18e87038b4fd4d3d258ed1c24c8821959b0880ea..8e916e79e98c27b6c9435859b8f018133e0b41bb 100644 --- a/src/Plugin/Action/ChangeUserWave.php +++ b/src/Plugin/Action/ChangeUserWave.php @@ -76,7 +76,7 @@ class ChangeUserWave extends ConfigurableActionBase implements ContainerFactoryP /** * {@inheritdoc} */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { + public function access($object, ?AccountInterface $account = NULL, $return_as_object = FALSE) { /** @var \Drupal\user\UserInterface $object */ $access = $object->access('update', $account, TRUE) ->andIf($object->roles->access('edit', $account, TRUE)); diff --git a/src/Plugin/Action/UnpublishByKeywordKnowledge.php b/src/Plugin/Action/UnpublishByKeywordKnowledge.php index 13e3cda1ad909042992c0cc73f950fe3af460de6..756a766a981a3bdc6fad432dab74c0f6819be388 100644 --- a/src/Plugin/Action/UnpublishByKeywordKnowledge.php +++ b/src/Plugin/Action/UnpublishByKeywordKnowledge.php @@ -117,7 +117,7 @@ class UnpublishByKeywordKnowledge extends ConfigurableActionBase implements Cont /** * {@inheritdoc} */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { + public function access($object, ?AccountInterface $account = NULL, $return_as_object = FALSE) { /** @var \Drupal\knowledge\KnowledgeInterface $object */ $result = $object->access('update', $account, TRUE) ->andIf($object->status->access('edit', $account, TRUE)); diff --git a/src/Plugin/Field/FieldFormatter/KnowledgeCompetencyFormatter.php b/src/Plugin/Field/FieldFormatter/KnowledgeCompetencyFormatter.php index 428e3e13377cc1afca9f62e713b5a382898196dd..9ed50f0770078bc44676f2f5fb62d120e3ccce97 100644 --- a/src/Plugin/Field/FieldFormatter/KnowledgeCompetencyFormatter.php +++ b/src/Plugin/Field/FieldFormatter/KnowledgeCompetencyFormatter.php @@ -6,7 +6,7 @@ use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\Plugin\Field\FieldFormatter\BooleanFormatter; /** - * Plugin implementation of the 'KnowledgeCompetency' formatter. + * Plugin implementation of the 'Competency' formatter. * * @FieldFormatter( * id = "knowledge_competency", @@ -23,10 +23,10 @@ class KnowledgeCompetencyFormatter extends BooleanFormatter { */ public function viewElements(FieldItemListInterface $items, $langcode) { $elements = parent::viewElements($items, $langcode); + $definition = $items->getFieldDefinition(); $description = $definition->getDescription(); foreach ($items as $delta => $item) { - // Here you can customize how the boolean field is displayed. $elements[$delta]['#suffix'] = '<div>' . $description . '</div><br/>'; } diff --git a/src/Plugin/Menu/LocalTask/UnapprovedKnowledge.php b/src/Plugin/Menu/LocalTask/UnapprovedKnowledge.php index bf057cc2c669002f99b51bc3a0d632415b77c6e8..885a27795dafdb5caedefaf9c3ba9970282d7f10 100644 --- a/src/Plugin/Menu/LocalTask/UnapprovedKnowledge.php +++ b/src/Plugin/Menu/LocalTask/UnapprovedKnowledge.php @@ -54,7 +54,7 @@ class UnapprovedKnowledge extends LocalTaskDefault implements ContainerFactoryPl /** * {@inheritdoc} */ - public function getTitle(Request $request = NULL) { + public function getTitle(?Request $request = NULL) { return $this->t('Unlinked knowledge (@count)', ['@count' => $this->knowledgeStorage->getUnapprovedCount()]); } diff --git a/src/Plugin/migrate/destination/EntityKnowledge.php b/src/Plugin/migrate/destination/EntityKnowledge.php index 4ea8bc9659d26801b874a28312fcdd0f328aeb76..f1c5eaca557086514ec41fbc3d22a21e3b82a84b 100644 --- a/src/Plugin/migrate/destination/EntityKnowledge.php +++ b/src/Plugin/migrate/destination/EntityKnowledge.php @@ -7,8 +7,8 @@ use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Field\FieldTypePluginManagerInterface; use Drupal\Core\Session\AccountSwitcherInterface; use Drupal\Core\State\StateInterface; -use Drupal\migrate\Plugin\migrate\destination\EntityContentBase; use Drupal\migrate\Plugin\MigrationInterface; +use Drupal\migrate\Plugin\migrate\destination\EntityContentBase; use Drupal\migrate\Row; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -59,7 +59,7 @@ class EntityKnowledge extends EntityContentBase { * @param \Drupal\Core\Session\AccountSwitcherInterface|null $account_switcher * The account switcher service. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, StateInterface $state, AccountSwitcherInterface $account_switcher = NULL) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage, array $bundles, EntityFieldManagerInterface $entity_field_manager, FieldTypePluginManagerInterface $field_type_manager, StateInterface $state, ?AccountSwitcherInterface $account_switcher = NULL) { parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $storage, $bundles, $entity_field_manager, $field_type_manager, $account_switcher); $this->state = $state; } @@ -67,7 +67,7 @@ class EntityKnowledge extends EntityContentBase { /** * {@inheritdoc} */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) { + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, ?MigrationInterface $migration = NULL) { $entity_type = static::getEntityTypeId($plugin_id); return new static( $configuration, diff --git a/src/Plugin/views/field/CompetencyApprove.php b/src/Plugin/views/field/CompetencyApprove.php index e3b6751e28f0a32723e3797bb47444123c644ad3..6ca44092d9adbd309cac0660356b2316294f2679 100644 --- a/src/Plugin/views/field/CompetencyApprove.php +++ b/src/Plugin/views/field/CompetencyApprove.php @@ -6,7 +6,7 @@ use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Link; use Drupal\Core\Path\CurrentPathStack; use Drupal\Core\Url; -use Drupal\user\Entity\Role; +use Drupal\knowledge\KnowledgeCompetencyServiceInterface; use Drupal\views\Plugin\views\field\FieldPluginBase; use Drupal\views\ResultRow; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -32,6 +32,13 @@ class CompetencyApprove extends FieldPluginBase { */ protected $pathCurrent; + /** + * The competency service. + * + * @var \Drupal\knowledge\KnowledgeCompetencyServiceInterface + */ + protected $competencyService; + /** * {@inheritdoc} */ @@ -41,12 +48,13 @@ class CompetencyApprove extends FieldPluginBase { $plugin_id, $plugin_definition, $container->get('entity_type.manager'), - $container->get('path.current') + $container->get('path.current'), + $container->get('knowledge.competency'), ); } /** - * Creates node type filter plugin. + * Creates knowledge competency filter plugin. * * @param array $configuration * A configuration array containing information about the plugin instance. @@ -58,11 +66,22 @@ class CompetencyApprove extends FieldPluginBase { * The entity type manager service. * @param \Drupal\Core\Path\CurrentPathStack $path_current * The renderer service. + * @param \Drupal\knowledge\KnowledgeCompetencyServiceInterface $competency_service + * The competency service. */ - public function __construct(array $configuration, string $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, CurrentPathStack $path_current) { + public function __construct( + array $configuration, + string $plugin_id, + $plugin_definition, + EntityTypeManagerInterface $entity_type_manager, + CurrentPathStack $path_current, + KnowledgeCompetencyServiceInterface $competency_service, + ) { parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->entityTypeManager = $entity_type_manager; $this->pathCurrent = $path_current; + $this->competencyService = $competency_service; } /** @@ -82,24 +101,11 @@ class CompetencyApprove extends FieldPluginBase { $current_path = $this->pathCurrent->getPath(); $link = NULL; - $competency_id = $this->entityTypeManager - ->getStorage('knowledge_competency') - ->getQuery() - ->condition('user_id', $entity_id) - ->accessCheck(FALSE) - ->execute(); - - if (!count($competency_id)) { - return $link; - } - $competency_id = current($competency_id); - /** @var \Drupal\knowledge\Entity\KnowledgeCompetencyInterface $competency */ - $competency = $this->entityTypeManager - ->getStorage('knowledge_competency') - ->load($competency_id); - if ($competency && $competency->isPending()) { - $role_id = $competency->isPendingPublisher() ? 'knowledge_publisher' : 'knowledge_contributor'; - $role = Role::load($role_id); + + $competency = $this->competencyService->getUserCompetency($entity_id); + $role_id = $competency->isPending(); + if ($role_id) { + $role = $this->competencyService->getPromotionRole($role_id); $text = $this->t('Promote to @role', ['@role' => $role->label()]); $current_url = Url::fromUri("internal:$current_path")->toString(); $url = Url::fromRoute( diff --git a/src/Plugin/views/field/LastTimestamp.php b/src/Plugin/views/field/LastTimestamp.php index 07b56f402d54a1f6ebe1caff2c3a2c20217f2fd7..61c6f3d479d0cabf2816c49200aff34535def6c9 100644 --- a/src/Plugin/views/field/LastTimestamp.php +++ b/src/Plugin/views/field/LastTimestamp.php @@ -19,7 +19,7 @@ class LastTimestamp extends Date { /** * {@inheritdoc} */ - public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { + public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL) { parent::init($view, $display, $options); $this->additional_fields['total_count'] = 'total_count'; diff --git a/src/Plugin/views/field/NodeNewKnowledge.php b/src/Plugin/views/field/NodeNewKnowledge.php index 7306d2c33b3541060927e8529cc1233aa871608f..0a156fd154afcdc5a8dedf9f4fb718cd4c2beace 100644 --- a/src/Plugin/views/field/NodeNewKnowledge.php +++ b/src/Plugin/views/field/NodeNewKnowledge.php @@ -111,7 +111,7 @@ class NodeNewKnowledge extends NumericField { /** * {@inheritdoc} */ - public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { + public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL) { parent::init($view, $display, $options); $this->additional_fields['entity_id'] = 'nid'; diff --git a/src/Plugin/views/filter/KnowledgeDisposition.php b/src/Plugin/views/filter/KnowledgeDisposition.php index 2cd08a4398bc8cfdbbd1c5d5b40f56d80ea4c5db..4ca3b25c41742f197b2fd2e78fda21ecfafb5de4 100644 --- a/src/Plugin/views/filter/KnowledgeDisposition.php +++ b/src/Plugin/views/filter/KnowledgeDisposition.php @@ -18,7 +18,7 @@ class KnowledgeDisposition extends InOperator { /** * {@inheritdoc} */ - public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { + public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL) { parent::init($view, $display, $options); $this->valueTitle = $this->t('Knowledge Disposition'); $this->definition['options callback'] = [$this, 'generateOptions']; diff --git a/src/Plugin/views/filter/KnowledgeLearners.php b/src/Plugin/views/filter/KnowledgeLearners.php index c59e3a02eb221b0e616123329a95cd9a53e49ede..d880485540dffae5afa6591eac868e73ec490a97 100644 --- a/src/Plugin/views/filter/KnowledgeLearners.php +++ b/src/Plugin/views/filter/KnowledgeLearners.php @@ -68,7 +68,7 @@ class KnowledgeLearners extends InOperator { /** * {@inheritdoc} */ - public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { + public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL) { parent::init($view, $display, $options); $this->valueTitle = $this->t('Learners'); $this->definition['options callback'] = [$this, 'generateOptions']; diff --git a/src/Plugin/views/filter/KnowledgeNodeType.php b/src/Plugin/views/filter/KnowledgeNodeType.php index b55a3b4cd294977ca7b06e7ca84257a8d9d03c78..055d83cccabc5189eacff28fa600be038e010f24 100644 --- a/src/Plugin/views/filter/KnowledgeNodeType.php +++ b/src/Plugin/views/filter/KnowledgeNodeType.php @@ -68,7 +68,7 @@ class KnowledgeNodeType extends InOperator { /** * {@inheritdoc} */ - public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) { + public function init(ViewExecutable $view, DisplayPluginBase $display, ?array &$options = NULL) { parent::init($view, $display, $options); $this->valueTitle = $this->t('Allowed node types'); $this->definition['options callback'] = [$this, 'generateOptions']; diff --git a/src/Service/CompetencyService.php b/src/Service/CompetencyService.php new file mode 100644 index 0000000000000000000000000000000000000000..ae1d13cb6a92ce03f072b8939b435ab83ed80f07 --- /dev/null +++ b/src/Service/CompetencyService.php @@ -0,0 +1,362 @@ +<?php + +namespace Drupal\knowledge\Service; + +use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Messenger\MessengerTrait; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\knowledge\KnowledgeCompetencyServiceInterface; +use Drupal\user\UserInterface; + +/** + * Service for the Competency entity. + */ +class CompetencyService implements KnowledgeCompetencyServiceInterface { + use StringTranslationTrait; + use MessengerTrait; + + /** + * The settings. + * + * @var \Drupal\Core\Config\ImmutableConfig + */ + protected $settings; + + /** + * The competency storage. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $competencyStorage; + + /** + * The user role storage. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $userRoleStorage; + + /** + * Constructs a new CompetencyService object. + * + * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory + * The config factory. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + * @param mixed $string_translation + * The string translation service. + * @param mixed $messenger + * The messenger service. + */ + public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, $string_translation, $messenger) { + $this->settings = $config_factory->get('knowledge.competency.settings'); + $this->competencyStorage = $entity_type_manager->getStorage('knowledge_competency'); + $this->userRoleStorage = $entity_type_manager->getStorage('user_role'); + $this->setStringTranslation($string_translation); + $this->setMessenger($messenger); + } + + /** + * {@inheritdoc} + */ + public function get() { + $setting = $this->settings->get('roles') ?? []; + usort($setting, [static::class, 'sort']); + + return $setting; + } + + /** + * {@inheritdoc} + */ + public function getUserCompetency($user_id) { + $query = $this->competencyStorage->getQuery(); + $result = $query + ->condition('user_id', $user_id) + ->accessCheck(FALSE) + ->execute(); + $competency = NULL; + if (count($result) == 1) { + $competency = $this->competencyStorage->load(current($result)); + } + if (count($result) == 0) { + $competency = $this->competencyStorage->create([ + 'user_id' => $user_id, + ]); + } + + return $competency; + } + + /** + * {@inheritdoc} + */ + public function getRoleIds() { + $roles = $this->get(); + $role_ids = []; + foreach ($roles as $role) { + $role_ids[] = $role['role']; + } + return $role_ids; + } + + /** + * {@inheritdoc} + */ + public function hasRoleOrBetter($role, $user_roles) { + if (in_array($role, $user_roles)) { + return TRUE; + } + + $roles = $this->getRoleIds(); + $role_index = array_search($role, $roles); + if ($role_index === FALSE) { + return FALSE; + } + + foreach (range($role_index + 1, count($roles) - 1) as $i) { + if (in_array($roles[$i] ?? NULL, $user_roles)) { + return TRUE; + } + } + + return FALSE; + } + + /** + * {@inheritdoc} + */ + public function doRoleRemoval(UserInterface &$user) { + $user_roles = $user->getRoles(TRUE); + $removable_roles = $this->getRemovableRoles($user_roles); + foreach ($removable_roles as $role) { + $user->removeRole($role); + } + } + + /** + * {@inheritdoc} + */ + public function doPreSave(&$roles, $orginal_roles) { + + $role_settings = $this->get(); + $sorted_roles = $this->getRoleIds(); + $existing_completed = []; + + foreach ($orginal_roles as $role) { + $completed = $role['total'] == $role['correct'] && $role['approved'] != NULL; + if ($completed) { + $existing_completed[] = $role['role']; + } + } + $new_roles = []; + foreach ($roles as $role) { + $role_name = $role->role; + $complete = $role->total == $role->correct; + if (!$complete) { + continue; + } + $exising = in_array($role_name, $existing_completed); + if ($exising || $role->proposed != NULL) { + continue; + } + $new_roles[] = $role_name; + } + + $completed_roles = []; + $settings = []; + foreach ($role_settings as $setting) { + $role = $setting['role']; + $settings[$role] = $setting; + $is_existing = in_array($role, $existing_completed); + $is_new = in_array($role, $new_roles); + $completed = !$is_existing && $is_new; + if ($completed) { + $completed_roles[] = $role; + } + elseif ($is_existing) { + continue; + } + else { + break; + } + } + + foreach ($roles as $role) { + $role_name = $role->role; + $completed = in_array($role_name, $completed_roles); + if (!$completed) { + continue; + } + $action = $settings[$role_name]['action'] ?? '_none'; + + $now = time(); + $curren_user_id = \Drupal::currentUser()->id(); + + switch ($action) { + + case 'auto': + $role->proposed = $now; + $role->proposer = $curren_user_id; + $role->approved = $now; + $role->approver = $curren_user_id; + break; + + case 'leader': + $role->proposed = $now; + $role->proposer = $curren_user_id; + break; + + case '_none': + default: + $role->proposed = $now; + $role->approved = $now; + break; + } + } + + } + + /** + * {@inheritdoc} + */ + public function doPostSave($user, $roles, $orginal_roles) { + $approved_roles = []; + foreach ($roles as $role) { + if ($role['approved'] != NULL) { + $approved_roles[] = $role['role']; + } + } + $orginal_approved_roles = []; + foreach ($orginal_roles as $role) { + if ($role['approved'] != NULL) { + $orginal_approved_roles[] = $role['role']; + } + } + + $new_approved_roles = array_diff($approved_roles, $orginal_approved_roles); + $settings = $this->get(); + $role_ids = $this->getRoleIds(); + $save_user = FALSE; + $user_roles = $user->getRoles(TRUE); + foreach ($settings as $setting) { + $role = $setting['role']; + if (!in_array($role, $new_approved_roles)) { + continue; + } + + $promote = $setting['promote'] ?? '_none'; + $promote_role_id = NULL; + switch ($promote) { + case 'self': + $needs_role = !$this->hasRoleOrBetter($role, $user_roles); + if ($needs_role) { + $user->addRole($role); + $promote_role_id = $role; + $save_user = TRUE; + } + break; + + case 'next': + $next_role = $role_ids[array_search($role, $role_ids) + 1] ?? NULL; + if (!is_null($next_role)) { + $needs_role = !$this->hasRoleOrBetter($next_role, $user_roles); + if ($needs_role) { + $user->addRole($next_role); + $promote_role_id = $next_role; + $save_user = TRUE; + } + } + break; + + case '_none': + default: + break; + } + + } + + if ($save_user) { + $user->save(); + $promote_role = $this->userRoleStorage->load($promote_role_id); + $this->messenger()->addMessage($this->t('%user was promoted to %role.', [ + '%role' => $promote_role->label(), + '%user' => $user->getDisplayName(), + ])); + } + + } + + /** + * {@inheritdoc} + */ + public function getPromotionRole($role_id) { + $roles = $this->get(); + $role_ids = $this->getRoleIds(); + $role_index = array_search($role_id, $role_ids); + if ($role_index === FALSE) { + return NULL; + } + + $next_role = $role_ids[$role_index + 1] ?? NULL; + + $settings = $this->get(); + $role_settings = []; + foreach ($settings as $setting) { + $role_settings[$setting['role']] = $setting; + } + + $promote = $role_settings[$role_id]['promote'] ?? '_none'; + switch ($promote) { + case 'self': + return $role_id; + + case 'next': + return $next_role; + + case '_none': + default: + return NULL; + } + + } + + /** + * Get the roles that can be removed. + * + * @param array $user_roles + * The user roles. + * + * @return array + * The roles that can be removed. + */ + private function getRemovableRoles($user_roles) { + + $removable_roles = []; + $best_role = NULL; + $roles = $this->getRoleIds(); + foreach ($roles as $index => $role) { + if (in_array($role, $user_roles)) { + if (!is_null($best_role)) { + $removable_roles[] = $best_role; + } + + $best_role = $role; + } + } + + return $removable_roles; + } + + /** + * Callback for usort. + */ + private static function sort($a, $b) { + if ($a['weight'] == $b['weight']) { + return 0; + } + return ($a['weight'] < $b['weight']) ? -1 : 1; + } + +} diff --git a/src/Service/KnowledgeLeaderService.php b/src/Service/KnowledgeLeaderService.php index 2881c598cb106f3c8fc5cd7c29871a80ba5f91da..88a4ade4c6d04ebb2a7fc47353199405d1087641 100644 --- a/src/Service/KnowledgeLeaderService.php +++ b/src/Service/KnowledgeLeaderService.php @@ -95,7 +95,7 @@ class KnowledgeLeaderService implements KnowledgeLeaderInterface { $leader->removeRole('knowledge_leader'); $leader->save(); } - elseif (!in_array('knowledge_leader', $leader->getRoles())) { + elseif (!in_array('knowledge_leader', $leader->getRoles(TRUE))) { $leader->addRole('knowledge_leader'); $leader->save(); } diff --git a/tests/src/Functional/CompetencyPromotionTest.php b/tests/src/Functional/CompetencyPromotionTest.php new file mode 100644 index 0000000000000000000000000000000000000000..771128801f1139a773996787b6bed779e09c376f --- /dev/null +++ b/tests/src/Functional/CompetencyPromotionTest.php @@ -0,0 +1,476 @@ +<?php + +namespace Drupal\Tests\knowledge\Functional; + +use Drupal\Tests\BrowserTestBase; + +/** + * Tests knowledge administration and preview access. + * + * @group knowledge + */ +class CompetencyPromotionTest extends BrowserTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'knowledge', + 'node', + ]; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * The learner user. + * + * @var \Drupal\user\UserInterface + */ + protected $learner; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->learner = $this->drupalCreateUser([ + 'access knowledge', + 'access content', + 'view own knowledge_competency', + ]); + + } + + /** + * Tests role advancement, auto-promotion, current role. + */ + public function testCompetencyAutoSelf() { + $learner_id = $this->learner->id(); + $coach = $this->drupalCreateUser([ + 'edit learner knowledge_competency', + ]); + $this->drupalLogin($coach); + + $assert = $this->assertSession(); + + $competency_url = "user/$learner_id/competency"; + $edit_url = "user/$learner_id/edit"; + // The coach is not the learner's coach yet. + $this->drupalGet($competency_url); + $assert->statusCodeEquals(403); + + // The coach is the learner's coach. + $this->learner->knowledge_coach->target_id = $coach->id(); + $this->learner->save(); + + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Candidate'); + $this->assertSession()->pageTextContains('Contributor'); + $this->assertSession()->pageTextContains('Publisher'); + + $this->doCanidate(); + + $this->assertSession()->pageTextContains('was promoted to Candidate'); + + $this->doContributor(); + + $this->assertSession()->pageTextContains('was promoted to Contributor'); + + $this->doPublisher(); + + $this->assertSession()->pageTextContains('was promoted to Publisher'); + + } + + /** + * Tests role advancement, auto-promotion, next role. + */ + public function testCompetencyAutoNext() { + $config = \Drupal::service('config.factory')->getEditable('knowledge.competency.settings'); + $settings = $config->get('roles'); + foreach ($settings as $index => $value) { + $settings[$index]['promote'] = 'next'; + if ($value['role'] == 'publisher') { + $settings[$index]['promote'] = '_none'; + $settings[$index]['action'] = '_none'; + } + } + $config->set('roles', $settings)->save(); + + $coach = $this->drupalCreateUser([ + 'edit learner knowledge_competency', + ]); + $this->drupalLogin($coach); + + $assert = $this->assertSession(); + + $learner_id = $this->learner->id(); + $coach = $this->drupalCreateUser([ + 'edit learner knowledge_competency', + ]); + $this->drupalLogin($coach); + + $assert = $this->assertSession(); + + $competency_url = "user/$learner_id/competency"; + $edit_url = "user/$learner_id/edit"; + // The coach is not the learner's coach yet. + $this->drupalGet($competency_url); + $assert->statusCodeEquals(403); + + // The coach is the learner's coach. + $this->learner->knowledge_coach->target_id = $coach->id(); + $this->learner->save(); + + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Candidate'); + $this->assertSession()->pageTextContains('Contributor'); + $this->assertSession()->pageTextContains('Publisher'); + + $this->doCanidate(); + + $this->assertSession()->pageTextContains('was promoted to Contributor'); + + $this->doContributor(); + + $this->assertSession()->pageTextContains('was promoted to Publisher'); + + $this->doPublisher(); + + } + + /** + * Tests role advancement, leader appoval, corrunt role. + */ + public function testCompetencyLeaderSelf() { + $config = \Drupal::service('config.factory')->getEditable('knowledge.competency.settings'); + $settings = $config->get('roles'); + foreach ($settings as $index => $value) { + $settings[$index]['action'] = 'leader'; + } + $config->set('roles', $settings)->save(); + + $leader = $this->drupalCreateUser([ + 'view follower knowledge_competency', + ]); + $coach = $this->drupalCreateUser([ + 'edit learner knowledge_competency', + ]); + $this->drupalLogin($coach); + + $assert = $this->assertSession(); + + $learner_id = $this->learner->id(); + $competency_url = "user/$learner_id/competency"; + + // The coach is the learner's coach. + $this->learner->knowledge_coach->target_id = $coach->id(); + $this->learner->knowledge_leader->target_id = $leader->id(); + $this->learner->save(); + + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Candidate'); + $this->assertSession()->pageTextContains('Contributor'); + $this->assertSession()->pageTextContains('Publisher'); + + $this->doCanidate(); + + $this->drupalLogin($leader); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + + $this->drupalGet($competency_url . '/approve'); + $assert->statusCodeEquals(200); + + $this->assertSession()->pageTextContains('Candidate'); + $this->submitForm([], 'Promote'); + + $this->assertSession()->pageTextContains('was promoted to Candidate'); + + $this->drupalLogin($coach); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->doContributor(); + + $this->drupalLogin($leader); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + + $this->drupalGet($competency_url . '/approve'); + $assert->statusCodeEquals(200); + + $this->assertSession()->pageTextContains('Contributor'); + $this->submitForm([], 'Promote'); + + $this->assertSession()->pageTextContains('was promoted to Contributor'); + + $this->drupalLogin($coach); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->doPublisher(); + + $this->drupalLogin($leader); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + + $this->drupalGet($competency_url . '/approve'); + $assert->statusCodeEquals(200); + + $this->assertSession()->pageTextContains('Publisher'); + $this->submitForm([], 'Promote'); + + $this->assertSession()->pageTextContains('was promoted to Publisher'); + + } + + /** + * Tests role advancement, leader appoval, corrunt role. + */ + public function testCompetencyLeaderNext() { + $config = \Drupal::service('config.factory')->getEditable('knowledge.competency.settings'); + $settings = $config->get('roles'); + foreach ($settings as $index => $value) { + $settings[$index]['action'] = 'leader'; + $settings[$index]['promote'] = 'next'; + if ($value['role'] == 'knowledge_publisher') { + $settings[$index]['promote'] = '_none'; + $settings[$index]['action'] = '_none'; + } + } + $config->set('roles', $settings)->save(); + + $leader = $this->drupalCreateUser([ + 'view follower knowledge_competency', + ]); + $coach = $this->drupalCreateUser([ + 'edit learner knowledge_competency', + ]); + $this->drupalLogin($coach); + + $assert = $this->assertSession(); + + $learner_id = $this->learner->id(); + $competency_url = "user/$learner_id/competency"; + + // The coach is the learner's coach. + $this->learner->knowledge_coach->target_id = $coach->id(); + $this->learner->knowledge_leader->target_id = $leader->id(); + $this->learner->save(); + + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Candidate'); + $this->assertSession()->pageTextContains('Contributor'); + $this->assertSession()->pageTextContains('Publisher'); + + $this->doCanidate(); + + $this->drupalLogin($leader); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + + $this->drupalGet($competency_url . '/approve'); + $assert->statusCodeEquals(200); + + $this->assertSession()->pageTextContains('Contributor'); + $this->submitForm([], 'Promote'); + + $this->assertSession()->pageTextContains('was promoted to Contributor'); + + $this->drupalLogin($coach); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->doContributor(); + + $this->drupalLogin($leader); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + + $this->drupalGet($competency_url . '/approve'); + $assert->statusCodeEquals(200); + + $this->assertSession()->pageTextContains('Publisher'); + $this->submitForm([], 'Promote'); + + $this->assertSession()->pageTextContains('was promoted to Publisher'); + + $this->drupalLogin($coach); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->doPublisher(); + + $this->drupalLogin($leader); + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + + $this->drupalGet($competency_url . '/approve'); + $assert->statusCodeEquals(404); + + // $this->assertSession()->pageTextContains('Publisher'); + // $this->submitForm([], 'Promote'); + // $this->assertSession()->pageTextContains('was promoted to Publisher'); + } + + /** + * Tests role advancement, _none, on role. + */ + public function testCompetencyNone() { + $config = \Drupal::service('config.factory')->getEditable('knowledge.competency.settings'); + $settings = $config->get('roles'); + foreach ($settings as $index => $value) { + $settings[$index]['action'] = '_none'; + $settings[$index]['promote'] = '_none'; + } + $config->set('roles', $settings)->save(); + + $learner_id = $this->learner->id(); + $coach = $this->drupalCreateUser([ + 'edit learner knowledge_competency', + ]); + $this->drupalLogin($coach); + + $assert = $this->assertSession(); + + $competency_url = "user/$learner_id/competency"; + $edit_url = "user/$learner_id/edit"; + // The coach is not the learner's coach yet. + $this->drupalGet($competency_url); + $assert->statusCodeEquals(403); + + // The coach is the learner's coach. + $this->learner->knowledge_coach->target_id = $coach->id(); + $this->learner->save(); + + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Candidate'); + $this->assertSession()->pageTextContains('Contributor'); + $this->assertSession()->pageTextContains('Publisher'); + + $this->doCanidate(); + + $this->assertSession()->pageTextNotContains('was promoted to Candidate'); + + $this->doContributor(); + + $this->assertSession()->pageTextNotContains('was promoted to Contributor'); + + $this->doPublisher(); + + $this->assertSession()->pageTextNotContains('was promoted to Publisher'); + + } + + /** + * Tests role advancement, auto-promotion, current role. + */ + public function testCompetencyAutoSelfAll() { + $learner_id = $this->learner->id(); + $coach = $this->drupalCreateUser([ + 'edit learner knowledge_competency', + ]); + $this->drupalLogin($coach); + + $assert = $this->assertSession(); + + $competency_url = "user/$learner_id/competency"; + $edit_url = "user/$learner_id/edit"; + // The coach is not the learner's coach yet. + $this->drupalGet($competency_url); + $assert->statusCodeEquals(403); + + // The coach is the learner's coach. + $this->learner->knowledge_coach->target_id = $coach->id(); + $this->learner->save(); + + $this->drupalGet($competency_url); + $assert->statusCodeEquals(200); + $this->assertSession()->pageTextContains('Candidate'); + $this->assertSession()->pageTextContains('Contributor'); + $this->assertSession()->pageTextContains('Publisher'); + + $this->doPublisher(); + + $this->assertSession()->pageTextContains('was promoted to Publisher'); + + } + + /** + * Submit the form with Candidate values. + */ + protected function doCanidate() { + $this->submitForm([ + 'edit-field-search-it-value' => 1, + 'edit-field-link-it-value' => 1, + 'edit-field-flag-it-value' => 1, + ], 'Save'); + } + + /** + * Submit the form with Contributor values. + */ + protected function doContributor() { + $this->submitForm([ + 'edit-field-search-it-value' => 1, + 'edit-field-link-it-value' => 1, + 'edit-field-flag-it-value' => 1, + + 'edit-field-business-value' => 1, + 'edit-field-documents-request-value' => 1, + 'edit-field-fix-it-value' => 1, + 'edit-field-reuse-value' => 1, + 'edit-field-kcs-article-elements-value' => 1, + 'edit-field-structure-value' => 1, + 'edit-field-complete-thoughts-value' => 1, + 'edit-field-one-value' => 1, + 'edit-field-includes-context-value' => 1, + 'edit-field-update-or-create-value' => 1, + 'edit-field-solve-loop-value' => 1, + + ], 'Save'); + } + + /** + * Submit the form with publisher values. + */ + protected function doPublisher() { + $this->submitForm([ + 'edit-field-search-it-value' => 1, + 'edit-field-link-it-value' => 1, + 'edit-field-flag-it-value' => 1, + + 'edit-field-business-value' => 1, + 'edit-field-documents-request-value' => 1, + 'edit-field-fix-it-value' => 1, + 'edit-field-reuse-value' => 1, + 'edit-field-kcs-article-elements-value' => 1, + 'edit-field-structure-value' => 1, + 'edit-field-complete-thoughts-value' => 1, + 'edit-field-one-value' => 1, + 'edit-field-includes-context-value' => 1, + 'edit-field-update-or-create-value' => 1, + 'edit-field-solve-loop-value' => 1, + + 'edit-field-capture-context-value' => 1, + 'edit-field-audience-value' => 1, + 'edit-field-content-standard-value' => 1, + 'edit-field-sufficient-to-solve-value' => 1, + 'edit-field-relevant-value' => 1, + 'edit-field-iterative-search-value' => 1, + 'edit-field-improve-value' => 1, + 'edit-field-process-adherence-value' => 1, + 'edit-field-confidence-value' => 1, + 'edit-field-capture-in-the-moment-value' => 1, + 'edit-field-collaborate-value' => 1, + + ], 'Save'); + } + +} diff --git a/tests/src/Functional/KnowledgeAccessTest.php b/tests/src/Functional/KnowledgeAccessTest.php index 8deea28e99b50fa0cff9f650492857b72b10242e..49a6d624969e7ddc63d148537324f7ab8dd909df 100644 --- a/tests/src/Functional/KnowledgeAccessTest.php +++ b/tests/src/Functional/KnowledgeAccessTest.php @@ -2,10 +2,10 @@ namespace Drupal\Tests\knowledge\Functional; +use Drupal\Tests\BrowserTestBase; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\node\Entity\NodeType; -use Drupal\Tests\BrowserTestBase; /** * Tests knowledge administration and preview access. diff --git a/tests/src/Functional/KnowledgeBookTest.php b/tests/src/Functional/KnowledgeBookTest.php deleted file mode 100644 index 6fa9b874d354065e3cf432310ea462f36bfb728c..0000000000000000000000000000000000000000 --- a/tests/src/Functional/KnowledgeBookTest.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php - -namespace Drupal\Tests\knowledge\Functional; - -use Drupal\knowledge\Entity\Knowledge; -use Drupal\knowledge\KnowledgeInterface; -use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\node\Entity\Node; -use Drupal\Tests\BrowserTestBase; - -/** - * Tests visibility of knowledge on book pages. - * - * @group knowledge - */ -class KnowledgeBookTest extends BrowserTestBase { - - use KnowledgeTestTrait; - - /** - * Modules to install. - * - * @var array - */ - protected static $modules = ['book', 'knowledge']; - - /** - * {@inheritdoc} - */ - protected $defaultTheme = 'stark'; - - /** - * {@inheritdoc} - */ - protected function setUp(): void { - parent::setUp(); - - // Create knowledge field on book. - $this->addDefaultKnowledgeField('node', 'book'); - } - - /** - * Tests knowledge in book export. - */ - public function testBookKnowledgePrint() { - $book_node = Node::create([ - 'type' => 'book', - 'title' => 'Book title', - 'body' => 'Book body', - ]); - $book_node->book['bid'] = 'new'; - $book_node->save(); - - $knowledge = Knowledge::create([ - 'entity_id' => $book_node->id(), - 'entity_type' => 'node', - 'field_name' => 'knowledge', - 'status' => KnowledgeInterface::PUBLISHED, - ]); - $knowledge->save(); - - $knowledge_user = $this->drupalCreateUser([ - 'access printer-friendly version', - 'access knowledge', - 'post knowledge', - ]); - $this->drupalLogin($knowledge_user); - - $this->drupalGet('node/' . $book_node->id()); - - $this->assertSession()->pageTextContains('Add new knowledge'); - // Ensure that the knowledge form subject field exists. - $this->assertSession()->fieldExists('subject[0][value]'); - - $this->drupalGet('book/export/html/' . $book_node->id()); - - $this->assertSession()->pageTextContains('Knowledge'); - - $this->assertSession()->pageTextNotContains('Add new knowledge'); - // Verify that the knowledge form subject field is not found. - $this->assertSession()->fieldNotExists('subject[0][value]'); - } - -} diff --git a/tests/src/Functional/KnowledgeCSSTest.php b/tests/src/Functional/KnowledgeCSSTest.php index 3f3c0083e9b343cc16814f26fd130edcc0e1c0e4..799ca8e96ae0fa60c489f17043aa1f99420c1c5d 100644 --- a/tests/src/Functional/KnowledgeCSSTest.php +++ b/tests/src/Functional/KnowledgeCSSTest.php @@ -3,9 +3,9 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Core\Language\LanguageInterface; +use Drupal\Tests\Traits\Core\GeneratePermutationsTrait; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\KnowledgeInterface; -use Drupal\Tests\Traits\Core\GeneratePermutationsTrait; use Drupal\user\RoleInterface; /** diff --git a/tests/src/Functional/KnowledgeCacheTagsTest.php b/tests/src/Functional/KnowledgeCacheTagsTest.php index c1ccce745b5492af5e8d6931f33342ccff09fbf0..95e869219ad5f9fb77188399ff3e9dce2394f7b2 100644 --- a/tests/src/Functional/KnowledgeCacheTagsTest.php +++ b/tests/src/Functional/KnowledgeCacheTagsTest.php @@ -4,13 +4,13 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Language\LanguageInterface; +use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\field\Entity\FieldConfig; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\KnowledgeInterface; use Drupal\knowledge\KnowledgeManagerInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; diff --git a/tests/src/Functional/KnowledgeEntityTest.php b/tests/src/Functional/KnowledgeEntityTest.php index 6dd0ea9b7a7c512a77adc82cbb3cef55b1f808f1..55b0506d4573f035331d4b55f8f6f8ae5722b22a 100644 --- a/tests/src/Functional/KnowledgeEntityTest.php +++ b/tests/src/Functional/KnowledgeEntityTest.php @@ -3,11 +3,11 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Core\Language\LanguageInterface; +use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Entity\KnowledgeType; use Drupal\knowledge\KnowledgeInterface; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; -use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait; /** * Tests knowledge with other entities. diff --git a/tests/src/Functional/KnowledgeLanguageTest.php b/tests/src/Functional/KnowledgeLanguageTest.php index c80811a54e0a0c85f1bcb67661ff82bd3441542a..c8c9b221caa355fa4ad861a7a76a93afe986fb82 100644 --- a/tests/src/Functional/KnowledgeLanguageTest.php +++ b/tests/src/Functional/KnowledgeLanguageTest.php @@ -3,11 +3,11 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Component\Render\FormattableMarkup; +use Drupal\Tests\BrowserTestBase; use Drupal\field\Entity\FieldStorageConfig; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\BrowserTestBase; /** * Tests for knowledge language. diff --git a/tests/src/Functional/KnowledgeNonNodeTest.php b/tests/src/Functional/KnowledgeNonNodeTest.php index cab1e5bb9859dfb1ef26e950f91763167e31c92f..db577b6d375472dd82ca8c754b7ac417e6848893 100644 --- a/tests/src/Functional/KnowledgeNonNodeTest.php +++ b/tests/src/Functional/KnowledgeNonNodeTest.php @@ -3,6 +3,8 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Core\Entity\EntityInterface; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\entity_test\Entity\EntityTest; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; @@ -11,8 +13,6 @@ use Drupal\knowledge\Entity\KnowledgeType; use Drupal\knowledge\KnowledgeInterface; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\field_ui\Traits\FieldUiTestTrait; use Drupal\user\RoleInterface; /** @@ -200,7 +200,7 @@ class KnowledgeNonNodeTest extends BrowserTestBase { * @return bool * Boolean indicating whether the knowledge was found. */ - public function knowledgeExists(KnowledgeInterface $knowledge = NULL, $reply = FALSE) { + public function knowledgeExists(?KnowledgeInterface $knowledge = NULL, $reply = FALSE) { if ($knowledge) { $regex = '/' . ($reply ? '<div class="indented">(.*?)' : ''); $regex .= '<article(.*?)id="knowledge-' . $knowledge->id() . '"(.*?)'; diff --git a/tests/src/Functional/KnowledgePreviewTest.php b/tests/src/Functional/KnowledgePreviewTest.php index 9a364e1c79179e29cd780833e06630c6faa9ad33..5a72fe674fb73efd07271612e11ff1d9947696de 100644 --- a/tests/src/Functional/KnowledgePreviewTest.php +++ b/tests/src/Functional/KnowledgePreviewTest.php @@ -4,9 +4,9 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Component\Render\MarkupInterface; use Drupal\Core\Datetime\DrupalDateTime; +use Drupal\Tests\TestFileCreationTrait; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\KnowledgeManagerInterface; -use Drupal\Tests\TestFileCreationTrait; /** * Tests knowledge preview. diff --git a/tests/src/Functional/KnowledgeRssTest.php b/tests/src/Functional/KnowledgeRssTest.php index 6f1ca84c6058c9eec4c91769bd40f6f0ee80842a..5b0b2317734050d4da4b76808f370d583de4a75b 100644 --- a/tests/src/Functional/KnowledgeRssTest.php +++ b/tests/src/Functional/KnowledgeRssTest.php @@ -4,8 +4,8 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Core\Cache\Cache; use Drupal\Core\Entity\Entity\EntityViewDisplay; -use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait; +use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; /** * Tests knowledge as part of an RSS feed. diff --git a/tests/src/Functional/KnowledgeStatusFieldAccessTest.php b/tests/src/Functional/KnowledgeStatusFieldAccessTest.php index 82a6130ddc6df5f6580ff12d142dd18a160da969..43e56074c9df3642451ee959508c0dfafd440173 100644 --- a/tests/src/Functional/KnowledgeStatusFieldAccessTest.php +++ b/tests/src/Functional/KnowledgeStatusFieldAccessTest.php @@ -2,9 +2,9 @@ namespace Drupal\Tests\knowledge\Functional; +use Drupal\Tests\BrowserTestBase; use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\node\Entity\NodeType; -use Drupal\Tests\BrowserTestBase; /** * Tests knowledge status field access. diff --git a/tests/src/Functional/KnowledgeTestBase.php b/tests/src/Functional/KnowledgeTestBase.php index 8ead869b567431a119b30a58af370ebd73015e90..5bbd599f670449e495532d438ba1c2fcb327e38a 100644 --- a/tests/src/Functional/KnowledgeTestBase.php +++ b/tests/src/Functional/KnowledgeTestBase.php @@ -4,6 +4,7 @@ namespace Drupal\Tests\knowledge\Functional; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\Tests\BrowserTestBase; use Drupal\field\Entity\FieldConfig; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Entity\KnowledgeType; @@ -11,7 +12,6 @@ use Drupal\knowledge\KnowledgeInterface; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\node\Entity\NodeType; -use Drupal\Tests\BrowserTestBase; /** * Provides setup and helper methods for knowledge tests. @@ -209,7 +209,7 @@ abstract class KnowledgeTestBase extends BrowserTestBase { * @return bool * Boolean indicating whether the knowledge was found. */ - public function knowledgeExists(KnowledgeInterface $knowledge = NULL, $reply = FALSE) { + public function knowledgeExists(?KnowledgeInterface $knowledge = NULL, $reply = FALSE) { if ($knowledge) { $knowledge_element = $this->cssSelect(($reply ? '.indented ' : '') . 'article#knowledge-' . $knowledge->id()); if (empty($knowledge_element)) { diff --git a/tests/src/Functional/KnowledgeTranslationUITest.php b/tests/src/Functional/KnowledgeTranslationUITest.php index dad2cebb933f7d62fd5ae3554e5b374bb9fb6d27..faa0e11167bd96784872d969febca2396ecc16f4 100644 --- a/tests/src/Functional/KnowledgeTranslationUITest.php +++ b/tests/src/Functional/KnowledgeTranslationUITest.php @@ -2,10 +2,10 @@ namespace Drupal\Tests\knowledge\Functional; +use Drupal\Tests\content_translation\Functional\ContentTranslationUITestBase; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\Tests\content_translation\Functional\ContentTranslationUITestBase; /** * Tests the Knowledge Translation UI. diff --git a/tests/src/Functional/Rest/KnowledgeResourceTestBase.php b/tests/src/Functional/Rest/KnowledgeResourceTestBase.php index 5c99e74e8c2d5c5d2ded7dd4dd9f3707b6778762..0964928bc52d92a817679f87bbf868bc30b3ac5d 100644 --- a/tests/src/Functional/Rest/KnowledgeResourceTestBase.php +++ b/tests/src/Functional/Rest/KnowledgeResourceTestBase.php @@ -3,11 +3,11 @@ namespace Drupal\Tests\knowledge\Functional\Rest; use Drupal\Core\Cache\Cache; +use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Entity\KnowledgeType; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase; use Drupal\user\Entity\User; use GuzzleHttp\RequestOptions; diff --git a/tests/src/Functional/Rest/KnowledgeTypeResourceTestBase.php b/tests/src/Functional/Rest/KnowledgeTypeResourceTestBase.php index 17719863f17a2cfee0f8b62cdf731bb0195a1a33..14efc0cad7909470a4f4da80ea611401caf5a6f7 100644 --- a/tests/src/Functional/Rest/KnowledgeTypeResourceTestBase.php +++ b/tests/src/Functional/Rest/KnowledgeTypeResourceTestBase.php @@ -2,8 +2,8 @@ namespace Drupal\Tests\knowledge\Functional\Rest; -use Drupal\knowledge\Entity\KnowledgeType; use Drupal\Tests\rest\Functional\EntityResource\ConfigEntityResourceTestBase; +use Drupal\knowledge\Entity\KnowledgeType; /** * ResourceTestBase for KnowledgeType entity. diff --git a/tests/src/Functional/Views/DefaultViewRecentKnowledgesTest.php b/tests/src/Functional/Views/DefaultViewRecentKnowledgesTest.php index b9a9b64fb3d3f9345e4681afba054ff18aab56d1..eb029d2e4ec6272cfded755f1e969727ef84e639 100644 --- a/tests/src/Functional/Views/DefaultViewRecentKnowledgesTest.php +++ b/tests/src/Functional/Views/DefaultViewRecentKnowledgesTest.php @@ -3,10 +3,10 @@ namespace Drupal\Tests\knowledge\Functional\Views; use Drupal\Component\Render\FormattableMarkup; +use Drupal\Tests\views\Functional\ViewTestBase; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\KnowledgeInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\views\Functional\ViewTestBase; use Drupal\views\Views; /** diff --git a/tests/src/Functional/Views/KnowledgeAdminTest.php b/tests/src/Functional/Views/KnowledgeAdminTest.php index 30dc1bf20a8b28677c73d5de9e8314f830083bcc..af270c775bcca950669967d3107e64c36345391f 100644 --- a/tests/src/Functional/Views/KnowledgeAdminTest.php +++ b/tests/src/Functional/Views/KnowledgeAdminTest.php @@ -2,13 +2,13 @@ namespace Drupal\Tests\knowledge\Functional\Views; -use Drupal\block_content\Entity\BlockContent; -use Drupal\block_content\Entity\BlockContentType; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\Unicode; +use Drupal\Tests\knowledge\Functional\KnowledgeTestBase as KnowledgeBrowserTestBase; +use Drupal\block_content\Entity\BlockContent; +use Drupal\block_content\Entity\BlockContentType; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; -use Drupal\Tests\knowledge\Functional\KnowledgeTestBase as KnowledgeBrowserTestBase; use Drupal\user\RoleInterface; use Drupal\views\Views; diff --git a/tests/src/Functional/Views/KnowledgeTestBase.php b/tests/src/Functional/Views/KnowledgeTestBase.php index 49bc71a6322ccd2ae166e89d86c018d87dcb86cc..81f14bcefc60b139cb0d0cea8b4894944fc6b7eb 100644 --- a/tests/src/Functional/Views/KnowledgeTestBase.php +++ b/tests/src/Functional/Views/KnowledgeTestBase.php @@ -3,9 +3,9 @@ namespace Drupal\Tests\knowledge\Functional\Views; use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\Tests\views\Functional\ViewTestBase; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\views\Functional\ViewTestBase; /** * Provides setup and helper methods for knowledge views tests. diff --git a/tests/src/Functional/Views/WizardTest.php b/tests/src/Functional/Views/WizardTest.php index aaef4604b38d9b1cf1d8efe23fadc0180913086a..109cfb195d0a924c81f0a62b4e2e7ba3a0705737 100644 --- a/tests/src/Functional/Views/WizardTest.php +++ b/tests/src/Functional/Views/WizardTest.php @@ -2,8 +2,8 @@ namespace Drupal\Tests\knowledge\Functional\Views; -use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\Tests\views\Functional\Wizard\WizardTestBase; +use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\views\Views; /** diff --git a/tests/src/Kernel/KnowledgeActionsTest.php b/tests/src/Kernel/KnowledgeActionsTest.php index 53ceafef44fea9f042fb39eae2453a63fff3714c..732dc7f7be061b13f13f1435e4da6672a3b1e835 100644 --- a/tests/src/Kernel/KnowledgeActionsTest.php +++ b/tests/src/Kernel/KnowledgeActionsTest.php @@ -3,9 +3,9 @@ namespace Drupal\Tests\knowledge\Kernel; use Drupal\Core\Datetime\Entity\DateFormat; +use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\filter\Entity\FilterFormat; -use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Entity\KnowledgeType; use Drupal\knowledge\Tests\KnowledgeTestTrait; diff --git a/tests/src/Kernel/KnowledgeBaseFieldTest.php b/tests/src/Kernel/KnowledgeBaseFieldTest.php index 4d7861aed186b6fd030cfa895b556df4e408f08d..165ea728104bdf19af1a46253986fb9c7faf8ce8 100644 --- a/tests/src/Kernel/KnowledgeBaseFieldTest.php +++ b/tests/src/Kernel/KnowledgeBaseFieldTest.php @@ -41,7 +41,6 @@ class KnowledgeBaseFieldTest extends KernelTestBase { parent::setUp(); $this->installEntitySchema('knowledge_test_base_field'); $this->installEntitySchema('knowledge'); - $this->installSchema('system', ['sequences']); $this->installEntitySchema('user'); } diff --git a/tests/src/Kernel/KnowledgeDefaultFormatterCacheTagsTest.php b/tests/src/Kernel/KnowledgeDefaultFormatterCacheTagsTest.php index 76a7329e99a204b0dbbf2dfe4ccac8b1f2c94f93..2cf205f2bed6f347d1111157ff6f3709b9e9b39b 100644 --- a/tests/src/Kernel/KnowledgeDefaultFormatterCacheTagsTest.php +++ b/tests/src/Kernel/KnowledgeDefaultFormatterCacheTagsTest.php @@ -3,8 +3,8 @@ namespace Drupal\Tests\knowledge\Kernel; use Drupal\Core\Cache\Cache; -use Drupal\entity_test\Entity\EntityTest; use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; +use Drupal\entity_test\Entity\EntityTest; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\KnowledgeInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; diff --git a/tests/src/Kernel/KnowledgeFieldAccessTest.php b/tests/src/Kernel/KnowledgeFieldAccessTest.php index 5fe1ea4ece626bf1f6ae99fe506d39dee6a64b09..770defe676a227f7aa7ce8b42eab10fbb566548f 100644 --- a/tests/src/Kernel/KnowledgeFieldAccessTest.php +++ b/tests/src/Kernel/KnowledgeFieldAccessTest.php @@ -4,14 +4,14 @@ namespace Drupal\Tests\knowledge\Kernel; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Session\AnonymousUserSession; +use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; +use Drupal\Tests\Traits\Core\GeneratePermutationsTrait; use Drupal\entity_test\Entity\EntityTest; use Drupal\field\Entity\FieldConfig; -use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Entity\KnowledgeType; use Drupal\knowledge\KnowledgeInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\Traits\Core\GeneratePermutationsTrait; use Drupal\user\Entity\Role; use Drupal\user\RoleInterface; diff --git a/tests/src/Kernel/KnowledgeIntegrationTest.php b/tests/src/Kernel/KnowledgeIntegrationTest.php index 928e830b2cb3cd13edd009c637fa7992335d2766..e6d817cfd721686aa2f6de691c1d5fda358d74bc 100644 --- a/tests/src/Kernel/KnowledgeIntegrationTest.php +++ b/tests/src/Kernel/KnowledgeIntegrationTest.php @@ -5,12 +5,12 @@ namespace Drupal\Tests\knowledge\Kernel; use Drupal\Core\Database\Database; use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\Core\Entity\Entity\EntityViewMode; +use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; -use Drupal\KernelTests\KernelTestBase; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Entity\KnowledgeType; -use Drupal\Tests\user\Traits\UserCreationTrait; /** * Tests integration of knowledge with other components. @@ -49,7 +49,6 @@ class KnowledgeIntegrationTest extends KernelTestBase { $this->installEntitySchema('user'); $this->installEntitySchema('knowledge'); $this->installSchema('dblog', ['watchdog']); - $this->installSchema('system', ['sequences']); // Create a new 'knowledge' knowledge-type. KnowledgeType::create([ diff --git a/tests/src/Kernel/KnowledgeItemTest.php b/tests/src/Kernel/KnowledgeItemTest.php index 596c9b58aaf0f1f34a899520d9c2a9fd3b5ed256..19971ce6e275053ea9c2064a5bd3305aba63b0d3 100644 --- a/tests/src/Kernel/KnowledgeItemTest.php +++ b/tests/src/Kernel/KnowledgeItemTest.php @@ -3,11 +3,11 @@ namespace Drupal\Tests\knowledge\Kernel; use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Tests\field\Kernel\FieldKernelTestBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; use Drupal\knowledge\Tests\KnowledgeTestTrait; -use Drupal\Tests\field\Kernel\FieldKernelTestBase; /** * Tests the new entity API for the knowledge field type. diff --git a/tests/src/Kernel/KnowledgeOrphanTest.php b/tests/src/Kernel/KnowledgeOrphanTest.php index 35c2697ee755a32fc4f3a2efbc8a6ee95ca569fa..eb454c20b250f93a3e01b1efedf23920fa7b79cf 100644 --- a/tests/src/Kernel/KnowledgeOrphanTest.php +++ b/tests/src/Kernel/KnowledgeOrphanTest.php @@ -3,9 +3,9 @@ namespace Drupal\Tests\knowledge\Kernel; use Drupal\Core\Datetime\Entity\DateFormat; -use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; use Drupal\Tests\EntityViewTrait; +use Drupal\field\Entity\FieldStorageConfig; /** * Tests loading and rendering orphan knowledge. diff --git a/tests/src/Kernel/KnowledgeStringIdEntitiesTest.php b/tests/src/Kernel/KnowledgeStringIdEntitiesTest.php index 9c8e0c6b301bdc57ebb6ec10877368e624c27a1f..d9995bcc652399075818dc8d560640dd3d449e2b 100644 --- a/tests/src/Kernel/KnowledgeStringIdEntitiesTest.php +++ b/tests/src/Kernel/KnowledgeStringIdEntitiesTest.php @@ -2,8 +2,8 @@ namespace Drupal\Tests\knowledge\Kernel; -use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\KernelTestBase; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\knowledge\Entity\KnowledgeType; /** diff --git a/tests/src/Kernel/KnowledgeUninstallTest.php b/tests/src/Kernel/KnowledgeUninstallTest.php index 3564952d4d765e1c232a1c33ab4960d06b0d5279..7a5f29a2a02a408904232c830c388d3d807a7d53 100644 --- a/tests/src/Kernel/KnowledgeUninstallTest.php +++ b/tests/src/Kernel/KnowledgeUninstallTest.php @@ -3,8 +3,8 @@ namespace Drupal\Tests\knowledge\Kernel; use Drupal\Core\Extension\ModuleUninstallValidatorException; -use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\KernelTestBase; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\node\Entity\NodeType; diff --git a/tests/src/Kernel/Migrate/MigrateKnowledgeStubTest.php b/tests/src/Kernel/Migrate/MigrateKnowledgeStubTest.php index 28bc55b17c237d541e72479610032b3d957b4a3e..a410f9094b6198e22f72f3d838398fc452dd991b 100644 --- a/tests/src/Kernel/Migrate/MigrateKnowledgeStubTest.php +++ b/tests/src/Kernel/Migrate/MigrateKnowledgeStubTest.php @@ -2,10 +2,10 @@ namespace Drupal\Tests\knowledge\Kernel\Migrate; +use Drupal\Tests\migrate_drupal\Kernel\MigrateDrupalTestBase; use Drupal\knowledge\Entity\KnowledgeType; use Drupal\migrate_drupal\Tests\StubTestTrait; use Drupal\node\Entity\NodeType; -use Drupal\Tests\migrate_drupal\Kernel\MigrateDrupalTestBase; /** * Test stub creation for knowledge entities. @@ -28,7 +28,6 @@ class MigrateKnowledgeStubTest extends MigrateDrupalTestBase { parent::setUp(); $this->installEntitySchema('knowledge'); $this->installEntitySchema('node'); - $this->installSchema('system', ['sequences']); // Make sure uid 0 is created (default uid for knowledge is 0). $storage = \Drupal::entityTypeManager()->getStorage('user'); diff --git a/tests/src/Kernel/Views/FilterAndArgumentUserUidTest.php b/tests/src/Kernel/Views/FilterAndArgumentUserUidTest.php index c3edcddaae7fde1ef3b3a0d17012dc1735924751..39d49393666b198ab1d29dd813576b1670714ef7 100644 --- a/tests/src/Kernel/Views/FilterAndArgumentUserUidTest.php +++ b/tests/src/Kernel/Views/FilterAndArgumentUserUidTest.php @@ -2,13 +2,13 @@ namespace Drupal\Tests\knowledge\Kernel\Views; -use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\node\Traits\NodeCreationTrait; +use Drupal\Tests\user\Traits\UserCreationTrait; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\node\Entity\NodeType; -use Drupal\Tests\node\Traits\NodeCreationTrait; -use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\views\Tests\ViewResultAssertionTrait; use Drupal\views\Tests\ViewTestData; use Drupal\views\Views; @@ -57,7 +57,6 @@ class FilterAndArgumentUserUidTest extends KernelTestBase { */ public function testHandlers() { $this->installEntitySchema('user'); - $this->installSchema('system', ['sequences']); $this->installEntitySchema('node'); $this->installEntitySchema('knowledge'); $this->installSchema('knowledge', ['knowledge_entity_statistics']); diff --git a/tests/src/Kernel/Views/KnowledgeAdminViewTest.php b/tests/src/Kernel/Views/KnowledgeAdminViewTest.php index c5892fbf046fc711108a8562b08e7817ad50a356..0d6a42d60b379bcaae52bcf0696eb896bf0b2cde 100644 --- a/tests/src/Kernel/Views/KnowledgeAdminViewTest.php +++ b/tests/src/Kernel/Views/KnowledgeAdminViewTest.php @@ -2,11 +2,11 @@ namespace Drupal\Tests\knowledge\Kernel\Views; +use Drupal\Tests\views\Kernel\ViewsKernelTestBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Entity\KnowledgeType; use Drupal\language\Entity\ConfigurableLanguage; -use Drupal\Tests\views\Kernel\ViewsKernelTestBase; use Drupal\user\Entity\Role; use Drupal\user\Entity\User; use Drupal\views\Views; diff --git a/tests/src/Kernel/Views/KnowledgeFieldNameTest.php b/tests/src/Kernel/Views/KnowledgeFieldNameTest.php index a55eb359112f84b3f48badb017021eeecb75e25e..05f8ca46dcf9c57ebf87a2d7f0e2d734eecad0c8 100644 --- a/tests/src/Kernel/Views/KnowledgeFieldNameTest.php +++ b/tests/src/Kernel/Views/KnowledgeFieldNameTest.php @@ -3,13 +3,13 @@ namespace Drupal\Tests\knowledge\Kernel\Views; use Drupal\Core\Render\RenderContext; -use Drupal\field\Entity\FieldStorageConfig; use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\node\Traits\NodeCreationTrait; +use Drupal\Tests\user\Traits\UserCreationTrait; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\knowledge\Entity\Knowledge; use Drupal\knowledge\Tests\KnowledgeTestTrait; use Drupal\node\Entity\NodeType; -use Drupal\Tests\node\Traits\NodeCreationTrait; -use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\views\Tests\ViewResultAssertionTrait; use Drupal\views\Tests\ViewTestData; use Drupal\views\Views; @@ -63,7 +63,6 @@ class KnowledgeFieldNameTest extends KernelTestBase { $this->installEntitySchema('user'); $this->installEntitySchema('node'); $this->installEntitySchema('knowledge'); - $this->installSchema('system', ['sequences']); $this->installSchema('knowledge', ['knowledge_entity_statistics']); $this->installConfig(['filter']); diff --git a/tests/src/Kernel/Views/KnowledgeUserNameTest.php b/tests/src/Kernel/Views/KnowledgeUserNameTest.php index 71c3a08d1a7d5b9a395d85e2bef6795c132c19b3..5cb59ec961a8a97137fe55e30739082a896eca00 100644 --- a/tests/src/Kernel/Views/KnowledgeUserNameTest.php +++ b/tests/src/Kernel/Views/KnowledgeUserNameTest.php @@ -3,9 +3,9 @@ namespace Drupal\Tests\knowledge\Kernel\Views; use Drupal\Core\Session\AnonymousUserSession; +use Drupal\Tests\views\Kernel\ViewsKernelTestBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\knowledge\Entity\Knowledge; -use Drupal\Tests\views\Kernel\ViewsKernelTestBase; use Drupal\user\Entity\Role; use Drupal\user\Entity\User; use Drupal\views\Entity\View; diff --git a/tests/src/Kernel/Views/KnowledgeViewsFieldAccessTest.php b/tests/src/Kernel/Views/KnowledgeViewsFieldAccessTest.php index 1ab86e91659801ef5c338725f10820e4ad5996ff..1c004a971af3d5dbc5ba1b991a74727b90936da6 100644 --- a/tests/src/Kernel/Views/KnowledgeViewsFieldAccessTest.php +++ b/tests/src/Kernel/Views/KnowledgeViewsFieldAccessTest.php @@ -2,9 +2,9 @@ namespace Drupal\Tests\knowledge\Kernel\Views; +use Drupal\Tests\views\Kernel\Handler\FieldFieldAccessTestBase; use Drupal\entity_test\Entity\EntityTest; use Drupal\knowledge\Entity\Knowledge; -use Drupal\Tests\views\Kernel\Handler\FieldFieldAccessTestBase; use Drupal\user\Entity\User; /** diff --git a/tests/src/Unit/CompetencyAccessControlHandlerTest.php b/tests/src/Unit/CompetencyAccessControlHandlerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..9c080553deda62c3cecdd93981138fac94728127 --- /dev/null +++ b/tests/src/Unit/CompetencyAccessControlHandlerTest.php @@ -0,0 +1,579 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\knowledge\Unit; + +use Drupal\Core\Session\AccountInterface; +use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\CompetencyAccessControlHandler; +use Drupal\user\UserInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Tests the Competency access control handler. + * + * @coversDefaultClass \Drupal\knowledge\CompetencyAccessControlHandler + * CompetencyAccessControlHandler + * @group knowledge + */ +class CompetencyAccessControlHandlerTest extends UnitTestCase { + + /** + * The entity type. + * + * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityType; + + /** + * The competency access control handler. + * + * @var \Drupal\knowledge\CompetencyAccessControlHandler + */ + protected $accessHandler; + + /** + * The service container. + * + * @var \Symfony\Component\DependencyInjection\ContainerBuilder + */ + protected $container; + + /** + * The module handler. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $moduleHandler; + + /** + * The cache contexts manager. + * + * @var \Drupal\Core\Cache\Context\CacheContextsManager|\PHPUnit\Framework\MockObject\MockObject + */ + protected $cacheContextsManager; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->entityType = $this->createMock('Drupal\Core\Entity\EntityTypeInterface'); + + $this->container = new ContainerBuilder(); + + $this->moduleHandler = $this->createMock('Drupal\Core\Extension\ModuleHandlerInterface'); + $this->container->set('module_handler', $this->moduleHandler); + + // cache_contexts_manager. + $this->cacheContextsManager = $this->createMock('Drupal\Core\Cache\Context\CacheContextsManager'); + $this->container->set('cache_contexts_manager', $this->cacheContextsManager); + + \Drupal::setContainer($this->container); + + $this->accessHandler = new CompetencyAccessControlHandler($this->entityType); + } + + /** + * @covers ::checkAccess + */ + public function testCheckAccessViewOwn(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $field_item->expects($this->exactly(2)) + ->method('__get') + ->with('target_id') + ->willReturn(1); + + $owner = $this->createMock(UserInterface::class); + $owner->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + ['knowledge_coach', $field_item], + ['knowledge_leader', $field_item], + ]); + + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(13); + $account->method('hasPermission') + ->willReturnMap([ + ['view own knowledge_competency', TRUE], + ]); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $competency->expects($this->once()) + ->method('getOwnerId') + ->willReturn(13); + $competency->expects($this->exactly(2)) + ->method('getOwner') + ->willReturn($owner); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'view', $account], []], + ['knowledge_competency_access', [$competency, 'view', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'view', $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + + /** + * @covers ::checkAccess + */ + public function testCheckAccessViewAny(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $field_item->expects($this->exactly(2)) + ->method('__get') + ->with('target_id') + ->willReturn(15); + + $owner = $this->createMock(UserInterface::class); + $owner->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + ['knowledge_coach', $field_item], + ['knowledge_leader', $field_item], + ]); + + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(10); + $account->method('hasPermission') + ->willReturnMap([ + ['view any knowledge_competency', TRUE], + ]); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $competency->expects($this->once()) + ->method('getOwnerId') + ->willReturn(1); + $competency->expects($this->exactly(2)) + ->method('getOwner') + ->willReturn($owner); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'view', $account], []], + ['knowledge_competency_access', [$competency, 'view', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'view', $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + + /** + * @covers ::checkAccess + */ + public function testCheckAccessViewLearner(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $field_item->expects($this->once()) + ->method('__get') + ->with('target_id') + ->willReturn(10); + + $coach_field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $coach_field_item->expects($this->once()) + ->method('__get') + ->with('target_id') + ->willReturn(3); + + $owner = $this->createMock(UserInterface::class); + $owner->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + ['knowledge_coach', $coach_field_item], + ['knowledge_leader', $field_item], + ]); + + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(3); + $account->method('hasPermission') + ->willReturnMap([ + ['view learner knowledge_competency', TRUE], + ]); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $competency->expects($this->once()) + ->method('getOwnerId') + ->willReturn(1); + $competency->expects($this->exactly(2)) + ->method('getOwner') + ->willReturn($owner); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'view', $account], []], + ['knowledge_competency_access', [$competency, 'view', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'view', $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + + /** + * @covers ::checkAccess + */ + public function testCheckAccessViewFollower(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $field_item->expects($this->once()) + ->method('__get') + ->with('target_id') + ->willReturn(1); + + $coach_field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $coach_field_item->expects($this->once()) + ->method('__get') + ->with('target_id') + ->willReturn(10); + + $owner = $this->createMock(UserInterface::class); + $owner->expects($this->exactly(2)) + ->method('get') + ->willReturnMap([ + ['knowledge_coach', $coach_field_item], + ['knowledge_leader', $field_item], + ]); + + $account = $this->createMock(AccountInterface::class); + $account->expects($this->exactly(5)) + ->method('id') + ->willReturn(1); + $account->method('hasPermission') + ->willReturnMap([ + ['view follower knowledge_competency', TRUE], + ]); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $competency->expects($this->once()) + ->method('getOwnerId') + ->willReturn(9); + $competency->expects($this->exactly(2)) + ->method('getOwner') + ->willReturn($owner); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'view', $account], []], + ['knowledge_competency_access', [$competency, 'view', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'view', $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + + /** + * @covers ::checkAccess + */ + public function testCheckAccessDelete(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(1); + $account->method('hasPermission') + ->willReturnMap([ + ['administer knowledge_competency', TRUE], + ]); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'delete', $account], []], + ['knowledge_competency_access', [$competency, 'delete', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'delete', $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + + /** + * @covers ::checkAccess + */ + public function testUnknownOperation(): void { + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(1); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'unknown', $account], []], + ['knowledge_competency_access', [$competency, 'unknown', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'unknown', $account); + + $this->assertNotNull($result); + $this->assertFalse($result); + } + + /** + * @covers ::checkAccess + */ + public function testCheckAccessUpdate(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $field_item->expects($this->once()) + ->method('__get') + ->with('target_id') + ->willReturn(1); + + $owner = $this->createMock(UserInterface::class); + $owner->expects($this->once()) + ->method('id') + ->willReturn(3); + $owner->expects($this->once()) + ->method('get') + ->willReturnMap([ + ['knowledge_coach', $field_item], + ]); + + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(1); + $account->method('hasPermission') + ->willReturnMap([ + ['edit other knowledge_competency', TRUE], + ['edit learner knowledge_competency', TRUE], + ]); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $competency->expects($this->once()) + ->method('getOwner') + ->willReturn($owner); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'update', $account], []], + ['knowledge_competency_access', [$competency, 'update', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'update', $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + + /** + * @covers ::checkAccess + */ + public function testCheckAccessUpdateOwn(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $field_item = $this->createMock('Drupal\Core\Field\FieldItemListInterface'); + $field_item->expects($this->once()) + ->method('__get') + ->with('target_id') + ->willReturn(1); + + $owner = $this->createMock(UserInterface::class); + $owner->expects($this->once()) + ->method('id') + ->willReturn(10); + $owner->expects($this->once()) + ->method('get') + ->willReturnMap([ + ['knowledge_coach', $field_item], + ]); + + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(10); + $account->method('hasPermission') + ->willReturnMap([ + ['edit own knowledge_competency', TRUE], + ]); + + $language = $this->createMock('Drupal\Core\Language\LanguageInterface'); + $language->expects($this->once()) + ->method('getId') + ->willReturn('en'); + + $competency = $this->createMock('Drupal\knowledge\KnowledgeCompetencyInterface'); + $competency->expects($this->once()) + ->method('language') + ->willReturn($language); + $competency->expects($this->exactly(2)) + ->method('getEntityTypeId') + ->willReturn('knowledge_competency'); + + $competency->expects($this->once()) + ->method('getOwner') + ->willReturn($owner); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturnMap([ + ['entity_access', [$competency, 'update', $account], []], + ['knowledge_competency_access', [$competency, 'update', $account], []], + ]); + + $result = $this->accessHandler->access($competency, 'update', $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + + /** + * @covers ::checkCreateAccess + */ + public function testCreateAccess(): void { + $this->cacheContextsManager->expects($this->exactly(2)) + ->method('assertValidTokens') + ->with(['user.permissions']) + ->willReturn(TRUE); + + $account = $this->createMock(AccountInterface::class); + $account->method('id') + ->willReturn(1); + $account->method('hasPermission') + ->willReturnMap([ + ['add knowledge_competency', TRUE], + ]); + + $this->moduleHandler->expects($this->exactly(2)) + ->method('invokeAll') + ->willReturn([]); + + $result = $this->accessHandler->createAccess(NULL, $account); + + $this->assertNotNull($result); + $this->assertTrue($result); + } + +} diff --git a/tests/src/Unit/CompetencyHtmlRouteProviderTest.php b/tests/src/Unit/CompetencyHtmlRouteProviderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..cf03e1f00fdfc898e3a90057894e62b48415641c --- /dev/null +++ b/tests/src/Unit/CompetencyHtmlRouteProviderTest.php @@ -0,0 +1,184 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\knowledge\Unit; + +use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\CompetencyHtmlRouteProvider; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\Routing\RouteCollection; + +/** + * @coversDefaultClass \Drupal\knowledge\CompetencyHtmlRouteProvider + * @group knowledge + */ +class CompetencyHtmlRouteProviderTest extends UnitTestCase { + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityTypeManager; + + /** + * The entity field manager. + * + * @var \Drupal\Core\Entity\EntityFieldManagerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityFieldManager; + + /** + * The competency HTML route provider. + * + * @var \Drupal\knowledge\CompetencyHtmlRouteProvider + */ + protected $competencyHtmlRouteProvider; + + /** + * The service container. + * + * @var \Symfony\Component\DependencyInjection\ContainerBuilder + */ + protected $container; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->container = new ContainerBuilder(); + + // $this->stringTranslation = $this->getStringTranslationStub(); + // $this->container->set('string_translation', $this->stringTranslation); + $this->entityTypeManager = $this->createMock('\Drupal\Core\Entity\EntityTypeManagerInterface'); + $this->container->set('entity_type.manager', $this->entityTypeManager); + + $this->entityFieldManager = $this->createMock('\Drupal\Core\Entity\EntityFieldManagerInterface'); + $this->container->set('entity_field.manager', $this->entityFieldManager); + + \Drupal::setContainer($this->container); + + $this->competencyHtmlRouteProvider = new CompetencyHtmlRouteProvider($this->entityTypeManager, $this->entityFieldManager); + } + + /** + * Tests the getRoutes method. + * + * @covers ::getRoutes + * @covers ::getHistoryRoute + * @covers ::getRevisionRoute + * @covers ::getRevisionRevertRoute + * @covers ::getRevisionDeleteRoute + * @covers ::getSettingsFormRoute + * @covers ::getRoleFormRoute + */ + public function testGetRoutes(): void { + + // EntityTypeInterface $entity_type. + $entity_type = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface'); + $entity_type->expects($this->exactly(5)) + ->method('id') + ->willReturn('knowledge_competency'); + $entity_type->expects($this->exactly(3)) + ->method('getAdminPermission') + ->willReturn('administer knowledge_competency'); + $entity_type->expects($this->exactly(11)) + ->method('hasLinkTemplate') + ->willReturnMap([ + ['add-form', TRUE], + ['canonical', TRUE], + ['edit-form', TRUE], + ['version-history', TRUE], + ['delete-form', TRUE], + ['collection', TRUE], + ['delete-multiple-form', FALSE], + ['revision', TRUE], + ['revision_revert', TRUE], + ['revision_delete', TRUE], + ]); + $entity_type->expects($this->exactly(7)) + ->method('getLinkTemplate') + ->willReturnMap([ + ['add-form', '/admin/content/knowledge/competency/add'], + ['canonical', '/admin/content/knowledge/competency/{knowledge_competency}'], + ['version-history', '/admin/content/knowledge/competency/{knowledge_competency}/revisions'], + ['edit-form', '/admin/content/knowledge/competency/{knowledge_competency}/edit'], + ['delete-form', '/admin/content/knowledge/competency/{knowledge_competency}/delete'], + ['collection', '/admin/content/knowledge/competency'], + [ + 'revision', + '/admin/content/knowledge/competency/{knowledge_competency}/revisions/{knowledge_competency_revision}/view', + ], + [ + 'revision_revert', + '/admin/content/knowledge/competency/{knowledge_competency}/revisions/{knowledge_competency_revision}/revert', + ], + [ + 'revision_delete', + '/admin/content/knowledge/competency/{knowledge_competency}/revisions/{knowledge_competency_revision}/delete', + ], + ]); + + $routes = $this->competencyHtmlRouteProvider->getRoutes($entity_type); + + $this->assertNotNull($routes); + $this->assertInstanceOf(RouteCollection::class, $routes); + + } + + /** + * Tests the getRoutes method when some routes are NULL. + * + * @covers ::getRoutes + * @covers ::getHistoryRoute + * @covers ::getRevisionRoute + * @covers ::getRevisionRevertRoute + * @covers ::getRevisionDeleteRoute + * @covers ::getSettingsFormRoute + * @covers ::getRoleFormRoute + */ + public function testGetRoutesNotHas(): void { + + // EntityTypeInterface $entity_type. + $entity_type = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface'); + $entity_type->expects($this->exactly(5)) + ->method('id') + ->willReturn('knowledge_competency'); + $entity_type->expects($this->exactly(3)) + ->method('getAdminPermission') + ->willReturn('administer knowledge_competency'); + $entity_type->expects($this->exactly(11)) + ->method('hasLinkTemplate') + ->willReturnMap([ + ['add-form', TRUE], + ['canonical', TRUE], + ['edit-form', TRUE], + ['version-history', FALSE], + ['delete-form', TRUE], + ['collection', TRUE], + ['delete-multiple-form', FALSE], + ['revision', FALSE], + ['revision_revert', FALSE], + ['revision_delete', FALSE], + ]); + $entity_type->expects($this->exactly(3)) + ->method('getLinkTemplate') + ->willReturnMap([ + ['add-form', '/admin/content/knowledge/competency/add'], + ['canonical', '/admin/content/knowledge/competency/{knowledge_competency}'], + ['edit-form', '/admin/content/knowledge/competency/{knowledge_competency}/edit'], + ['delete-form', '/admin/content/knowledge/competency/{knowledge_competency}/delete'], + ['collection', '/admin/content/knowledge/competency'], + ]); + + $routes = $this->competencyHtmlRouteProvider->getRoutes($entity_type); + + $this->assertNotNull($routes); + $this->assertInstanceOf(RouteCollection::class, $routes); + + } + +} diff --git a/tests/src/Unit/CompetencyListBuilderTest.php b/tests/src/Unit/CompetencyListBuilderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..82ffd53df81d4b9cfbd934f320cbc7ea87fc5fce --- /dev/null +++ b/tests/src/Unit/CompetencyListBuilderTest.php @@ -0,0 +1,201 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\knowledge\Unit; + +use Drupal\Core\Access\AccessResult; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Routing\RedirectDestinationInterface; +use Drupal\Core\Url; +use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\CompetencyListBuilder; + +/** + * @coversDefaultClass \Drupal\knowledge\CompetencyListBuilder + * @group knowledge + */ +class CompetencyListBuilderTest extends UnitTestCase { + + /** + * The entity type used for testing. + * + * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityType; + + /** + * The module handler used for testing. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $moduleHandler; + + /** + * The translation manager used for testing. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface + */ + protected $translationManager; + + /** + * The competency storage used for testing. + * + * @var \Drupal\knowledge\KnowledgeCompetencyStorageInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $competencyStorage; + + /** + * The service container used for testing. + * + * @var \Drupal\Core\DependencyInjection\ContainerBuilder + */ + protected $container; + + /** + * The entity used to construct the EntityListBuilder. + * + * @var \Drupal\user\UserInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $user; + + /** + * The redirect destination service. + * + * @var \Drupal\Core\Routing\RedirectDestinationInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $redirectDestination; + + /** + * The EntityListBuilder object to test. + * + * @var \Drupal\knowledge\CompetencyListBuilder + */ + protected $competencyListBuilder; + + /** + * The string translation service. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface + */ + protected $stringTranslation; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->user = $this->createMock('Drupal\user\UserInterface'); + $this->stringTranslation = $this->getStringTranslationStub(); + $this->competencyStorage = $this->createMock('\Drupal\knowledge\KnowledgeCompetencyStorageInterface'); + $this->moduleHandler = $this->createMock('\Drupal\Core\Extension\ModuleHandlerInterface'); + $this->entityType = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface'); + $this->translationManager = $this->createMock('\Drupal\Core\StringTranslation\TranslationInterface'); + $this->competencyListBuilder = new CompetencyListBuilder($this->entityType, $this->competencyStorage); + $this->redirectDestination = $this->createMock(RedirectDestinationInterface::class); + $this->container = new ContainerBuilder(); + $this->container->set('module_handler', $this->moduleHandler); + $this->container->set('string_translation', $this->stringTranslation); + \Drupal::setContainer($this->container); + } + + /** + * @covers ::buildHeader + */ + public function testBuildHeader(): void { + $header = $this->competencyListBuilder->buildHeader(); + $this->assertIsArray($header); + $this->assertArrayHasKey('id', $header); + $this->assertArrayHasKey('user', $header); + $this->assertArrayHasKey('operations', $header); + } + + /** + * @covers ::buildRow + */ + public function testBuildRow() { + $entity = $this->createMock('\Drupal\knowledge\Entity\Competency'); + $entity->expects($this->exactly(2)) + ->method('id') + ->willReturn(1); + $entity->expects($this->once()) + ->method('getOwner') + ->willReturn($this->user); + $this->user->expects($this->once()) + ->method('label') + ->willReturn('test'); + $url = Url::fromRoute('entity.knowledge_competency.edit_form', ['knowledge_competency' => 1]); + + $operation_name = $this->randomMachineName(); + $operations = [ + $operation_name => [ + 'title' => $this->randomMachineName(), + ], + ]; + $this->moduleHandler->expects($this->once()) + ->method('invokeAll') + ->with('entity_operation', [$entity]) + ->willReturn($operations); + $this->moduleHandler->expects($this->once()) + ->method('alter') + ->with('entity_operation'); + + $row = $this->competencyListBuilder->buildRow($entity); + $this->assertIsArray($row); + $this->assertArrayHasKey('id', $row); + $this->assertArrayHasKey('user', $row); + $this->assertArrayHasKey('operations', $row); + } + + /** + * @covers ::getOperations + */ + public function testGetOperations(): void { + $operation_name = $this->randomMachineName(); + $operations = [ + $operation_name => [ + 'title' => $this->randomMachineName(), + ], + ]; + $this->moduleHandler->expects($this->once()) + ->method('invokeAll') + ->with('entity_operation', [$this->user]) + ->willReturn($operations); + $this->moduleHandler->expects($this->once()) + ->method('alter') + ->with('entity_operation'); + + $this->user->expects($this->any()) + ->method('access') + ->willReturn(AccessResult::allowed()); + $this->user->expects($this->any()) + ->method('hasLinkTemplate') + ->willReturn(TRUE); + $url = Url::fromRoute('entity.user_role.collection'); + $this->user->expects($this->any()) + ->method('toUrl') + ->willReturn($url); + + $this->redirectDestination->expects($this->atLeastOnce()) + ->method('getAsArray') + ->willReturn(['destination' => '/foo/bar']); + + $list = new CompetencyListBuilder($this->entityType, $this->competencyStorage); + $list->setStringTranslation($this->translationManager); + $list->setRedirectDestination($this->redirectDestination); + + $operations = $list->getOperations($this->user); + $this->assertIsArray($operations); + $this->assertArrayHasKey('edit', $operations); + $this->assertIsArray($operations['edit']); + $this->assertArrayHasKey('title', $operations['edit']); + $this->assertArrayHasKey('delete', $operations); + $this->assertIsArray($operations['delete']); + $this->assertArrayHasKey('title', $operations['delete']); + $this->assertArrayHasKey($operation_name, $operations); + $this->assertIsArray($operations[$operation_name]); + $this->assertArrayHasKey('title', $operations[$operation_name]); + } + +} diff --git a/tests/src/Unit/CompetencyStorageTest.php b/tests/src/Unit/CompetencyStorageTest.php new file mode 100644 index 0000000000000000000000000000000000000000..8aee8c892ddfd36ed3b11abff73afdf8ebb0914f --- /dev/null +++ b/tests/src/Unit/CompetencyStorageTest.php @@ -0,0 +1,202 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\knowledge\Unit; + +use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\CompetencyStorage; +use Drupal\knowledge\KnowledgeCompetencyInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * @coversDefaultClass \Drupal\knowledge\CompetencyStorage + * @group knowledge + */ +class CompetencyStorageTest extends UnitTestCase { + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityTypeManager; + + /** + * The entity field manager. + * + * @var \Drupal\Core\Entity\EntityFieldManagerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityFieldManager; + + /** + * The competency storage. + * + * @var \Drupal\knowledge\CompetencyStorage + */ + protected $competencyStorage; + + /** + * The service container. + * + * @var \Symfony\Component\DependencyInjection\ContainerBuilder + */ + protected $container; + + /** + * The entity type. + * + * @var \Drupal\Core\Entity\EntityTypeInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityType; + + /** + * The database connection. + * + * @var \Drupal\Core\Database\Connection|\PHPUnit\Framework\MockObject\MockObject + */ + protected $database; + + /** + * The cache backend. + * + * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $cache; + + /** + * The language manager. + * + * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $languageManager; + + /** + * The memory cache. + * + * @var \Drupal\Core\Cache\MemoryCache\MemoryCacheInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $memoryCache; + + /** + * The entity type bundle manager. + * + * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityTypeBundleManager; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->container = new ContainerBuilder(); + + // $this->stringTranslation = $this->getStringTranslationStub(); + // $this->container->set('string_translation', $this->stringTranslation); + $this->entityTypeManager = $this->createMock('\Drupal\Core\Entity\EntityTypeManager'); + $this->container->set('entity_type.manager', $this->entityTypeManager); + + $this->entityFieldManager = $this->createMock('\Drupal\Core\Entity\EntityFieldManager'); + $this->container->set('entity_field.manager', $this->entityFieldManager); + + $this->database = $this->createMock('\Drupal\Core\Database\Connection'); + $this->container->set('database', $this->database); + + $this->cache = $this->createMock('\Drupal\Core\Cache\CacheBackendInterface'); + $this->languageManager = $this->createMock('\Drupal\Core\Language\LanguageManager'); + $this->memoryCache = $this->createMock('\Drupal\Core\Cache\MemoryCache\MemoryCache'); + $this->entityTypeBundleManager = $this->createMock('\Drupal\Core\Entity\EntityTypeBundleInfo'); + + \Drupal::setContainer($this->container); + + $this->entityType = $this->createMock('\Drupal\Core\Entity\EntityTypeInterface'); + + } + + /** + * @covers ::revisionIds + */ + public function testRevisionIds() { + $entity = $this->createMock(KnowledgeCompetencyInterface::class); + $entity->expects($this->once()) + ->method('id') + ->willReturn(123); + $this->entityType->expects($this->exactly(3)) + ->method('id') + ->willReturn('knowledge_competency'); + + $entity_type = $this->createMock('\Drupal\Core\Entity\ContentEntityTypeInterface'); + $this->entityTypeManager->expects($this->once()) + ->method('getActiveDefinition') + ->with('knowledge_competency') + ->willReturn($entity_type); + + $this->entityFieldManager->expects($this->once()) + ->method('getActiveFieldStorageDefinitions') + ->with('knowledge_competency') + ->willReturn([]); + + $select_statement = $this->createMock('\Drupal\Core\Database\StatementInterface'); + $this->database->expects($this->once()) + ->method('query') + ->with('SELECT vid FROM {knowledge_competency_revision} WHERE id=:id ORDER BY vid', [':id' => 123]) + ->willReturn($select_statement); + + $competencyStorage = new CompetencyStorage( + $this->entityType, + $this->database, + $this->entityFieldManager, + $this->cache, + $this->languageManager, + $this->memoryCache, + $this->entityTypeBundleManager, + $this->entityTypeManager, + ); + $competencyStorage->revisionIds($entity); + } + + /** + * @covers ::userRevisionIds + */ + public function testUserRevisionIds() { + $account = $this->createMock('\Drupal\Core\Session\AccountInterface'); + $account->expects($this->once()) + ->method('id') + ->willReturn(123); + $this->entityType->expects($this->exactly(3)) + ->method('id') + ->willReturn('knowledge_competency'); + + $entity_type = $this->createMock('\Drupal\Core\Entity\ContentEntityTypeInterface'); + $this->entityTypeManager->expects($this->once()) + ->method('getActiveDefinition') + ->with('knowledge_competency') + ->willReturn($entity_type); + + $this->entityFieldManager->expects($this->once()) + ->method('getActiveFieldStorageDefinitions') + ->with('knowledge_competency') + ->willReturn([]); + + $select_statement = $this->createMock('\Drupal\Core\Database\StatementInterface'); + $this->database->expects($this->once()) + ->method('query') + ->with('SELECT vid FROM {knowledge_competency_field_revision} WHERE uid = :uid ORDER BY vid', [':uid' => 123]) + ->willReturn($select_statement); + + $competencyStorage = new CompetencyStorage( + $this->entityType, + $this->database, + $this->entityFieldManager, + $this->cache, + $this->languageManager, + $this->memoryCache, + $this->entityTypeBundleManager, + $this->entityTypeManager, + ); + $competencyStorage->userRevisionIds($account); + } + +} diff --git a/tests/src/Unit/KnowledgeLinkBuilderTest.php b/tests/src/Unit/KnowledgeLinkBuilderTest.php index 5e8ba4098b5d88be46fe1c66f68bf803f9dc0f64..937a6be93b73336fcb067d9a7ea09c80473b04e6 100644 --- a/tests/src/Unit/KnowledgeLinkBuilderTest.php +++ b/tests/src/Unit/KnowledgeLinkBuilderTest.php @@ -4,11 +4,10 @@ namespace Drupal\Tests\knowledge\Unit; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Url; +use Drupal\Tests\UnitTestCase; use Drupal\knowledge\KnowledgeLinkBuilder; use Drupal\knowledge\Plugin\Field\FieldType\KnowledgeItemInterface; use Drupal\node\NodeInterface; -use Drupal\Tests\Traits\Core\GeneratePermutationsTrait; -use Drupal\Tests\UnitTestCase; /** * @coversDefaultClass \Drupal\knowledge\KnowledgeLinkBuilder @@ -16,8 +15,6 @@ use Drupal\Tests\UnitTestCase; */ class KnowledgeLinkBuilderTest extends UnitTestCase { - use GeneratePermutationsTrait; - /** * Knowledge manager mock. * diff --git a/tests/src/Unit/KnowledgeManagerTest.php b/tests/src/Unit/KnowledgeManagerTest.php index a17800d1331022a29e2a62fc3f540939ae9e1b42..1bf7da6af3928fa33f2cc2a25e42e60d37a3f114 100644 --- a/tests/src/Unit/KnowledgeManagerTest.php +++ b/tests/src/Unit/KnowledgeManagerTest.php @@ -7,8 +7,8 @@ use Drupal\Core\Entity\EntityFieldManagerInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Session\AccountInterface; -use Drupal\knowledge\KnowledgeManager; use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\KnowledgeManager; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophet; diff --git a/tests/src/Unit/KnowledgeStatisticsUnitTest.php b/tests/src/Unit/KnowledgeStatisticsUnitTest.php index 926f55d35aa5cdfd337e1d78129a083b18c3fa40..feb4144b8c60e218475e1a0ae6fec4c1d2766f2c 100644 --- a/tests/src/Unit/KnowledgeStatisticsUnitTest.php +++ b/tests/src/Unit/KnowledgeStatisticsUnitTest.php @@ -2,8 +2,8 @@ namespace Drupal\Tests\knowledge\Unit; -use Drupal\knowledge\KnowledgeStatistics; use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\KnowledgeStatistics; /** * @coversDefaultClass \Drupal\knowledge\KnowledgeStatistics diff --git a/tests/src/Unit/Plugin/views/field/KnowledgeBulkFormTest.php b/tests/src/Unit/Plugin/views/field/KnowledgeBulkFormTest.php index 8b0280d981da0f8807adab70f0d7c1dfd75e15e1..de5bccb490e89e8dc06876a2a1a915df75767514 100644 --- a/tests/src/Unit/Plugin/views/field/KnowledgeBulkFormTest.php +++ b/tests/src/Unit/Plugin/views/field/KnowledgeBulkFormTest.php @@ -5,8 +5,8 @@ namespace Drupal\Tests\knowledge\Unit\Plugin\views\field; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\knowledge\Plugin\views\field\KnowledgeBulkForm; use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\Plugin\views\field\KnowledgeBulkForm; /** * @coversDefaultClass \Drupal\knowledge\Plugin\views\field\KnowledgeBulkForm @@ -67,6 +67,10 @@ class KnowledgeBulkFormTest extends UnitTestCase { ->will($this->returnValue(['table' => ['entity type' => 'knowledge']])); $container = new ContainerBuilder(); $container->set('views.views_data', $views_data); + + $route_match = $this->createMock('Drupal\Core\Routing\ResettableStackedRouteMatchInterface'); + $container->set('current_route_match', $route_match); + $container->set('string_translation', $this->getStringTranslationStub()); \Drupal::setContainer($container); @@ -84,7 +88,7 @@ class KnowledgeBulkFormTest extends UnitTestCase { $definition['title'] = ''; $options = []; - $knowledge_bulk_form = new KnowledgeBulkForm([], 'knowledge_bulk_form', $definition, $entity_type_manager, $language_manager, $messenger, $entity_repository); + $knowledge_bulk_form = new KnowledgeBulkForm([], 'knowledge_bulk_form', $definition, $entity_type_manager, $language_manager, $messenger, $entity_repository, $route_match); $knowledge_bulk_form->init($executable, $display, $options); $reflected_actions = (new \ReflectionObject($knowledge_bulk_form))->getProperty('actions'); diff --git a/tests/src/Unit/Service/CompetencyServiceTest.php b/tests/src/Unit/Service/CompetencyServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5d880bc0f5cf083fd2e32f5a2c63df3cc13430cd --- /dev/null +++ b/tests/src/Unit/Service/CompetencyServiceTest.php @@ -0,0 +1,419 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Tests\knowledge\Service\Unit; + +use Drupal\Tests\UnitTestCase; +use Drupal\knowledge\Service\CompetencyService; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * @coversDefaultClass \Drupal\knowledge\Service\CompetencyService + * @group knowledge + */ +class CompetencyServiceTest extends UnitTestCase { + + /** + * The config factory. + * + * @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $configFactory; + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $entityTypeManager; + + /** + * The service container. + * + * @var \Symfony\Component\DependencyInjection\ContainerBuilder + */ + protected $container; + + /** + * The string translation service. + * + * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $stringTranslation; + + /** + * The messenger service. + * + * @var \Drupal\Core\Messenger\MessengerInterface|\PHPUnit\Framework\MockObject\MockObject + */ + protected $messenger; + + /** + * {@inheritdoc} + */ + protected function setup(): void { + parent::setUp(); + + $this->container = new ContainerBuilder(); + + $this->configFactory = $this->createMock('\Drupal\Core\Config\ConfigFactoryInterface'); + $this->container->set('config.factory', $this->configFactory); + + $this->entityTypeManager = $this->createMock('\Drupal\Core\Entity\EntityTypeManagerInterface'); + $this->container->set('entity_type.manager', $this->entityTypeManager); + + $this->stringTranslation = $this->getStringTranslationStub(); + $this->container->set('string_translation', $this->stringTranslation); + + $this->messenger = $this->createMock('\Drupal\Core\Messenger\MessengerInterface'); + $this->container->set('messenger', $this->messenger); + + \Drupal::setContainer($this->container); + } + + /** + * Test get method. + * + * @covers ::get + * @covers ::sort + */ + public function testGet() { + $config = $this->createMock('\Drupal\Core\Config\ImmutableConfig'); + $config->expects($this->once()) + ->method('get') + ->with('roles') + ->willReturn([ + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 2, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_canidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + ]); + + $this->configFactory->expects($this->once()) + ->method('get') + ->with('knowledge.competency.settings') + ->willReturn($config); + + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + + $expected = [ + [ + 'role' => 'knowledge_canidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 2, + 'action' => 'auto', + 'promote' => 'self', + ], + ]; + $this->assertEquals($expected, $service->get()); + } + + /** + * Test get method. + * + * @covers ::get + * @covers ::sort + */ + public function testGetSameWeight() { + $config = $this->createMock('\Drupal\Core\Config\ImmutableConfig'); + $config->expects($this->once()) + ->method('get') + ->with('roles') + ->willReturn([ + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_canidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + ]); + + $this->configFactory->expects($this->once()) + ->method('get') + ->with('knowledge.competency.settings') + ->willReturn($config); + + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + + $expected = [ + [ + 'role' => 'knowledge_canidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + ]; + $this->assertEquals($expected, $service->get()); + } + + /** + * Test __construct method. + * + * @covers ::__construct + */ + public function testConstruct() { + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + $this->assertInstanceOf(CompetencyService::class, $service); + } + + /** + * Test getRoleIds method. + * + * @covers ::getRoleIds + */ + public function testGetRoleIds(): void { + $config = $this->createMock('\Drupal\Core\Config\ImmutableConfig'); + $config->expects($this->once()) + ->method('get') + ->with('roles') + ->willReturn([ + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 2, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_canidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + ]); + + $this->configFactory->expects($this->once()) + ->method('get') + ->with('knowledge.competency.settings') + ->willReturn($config); + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + $this->assertEquals(['knowledge_canidate', 'knowledge_contributor', 'knowledge_publisher'], $service->getRoleIds()); + } + + /** + * Test hasRoleOrBotter method. + * + * @covers ::hasRoleOrBetter + */ + public function testHasRoleOrBetter(): void { + $config = $this->createMock('\Drupal\Core\Config\ImmutableConfig'); + $config->expects($this->exactly(3)) + ->method('get') + ->with('roles') + ->willReturn([ + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 2, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_canidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + ]); + + $this->configFactory->expects($this->once()) + ->method('get') + ->with('knowledge.competency.settings') + ->willReturn($config); + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + + $user_roles = ['authenticated', 'knowledge_contributor']; + $this->assertTrue($service->hasRoleOrBetter('knowledge_canidate', $user_roles)); + $this->assertTrue($service->hasRoleOrBetter('knowledge_contributor', $user_roles)); + $this->assertFalse($service->hasRoleOrBetter('knowledge_publisher', $user_roles)); + $this->assertFalse($service->hasRoleOrBetter('knowledge_botter', $user_roles)); + } + + /** + * Test getUserCompetency method. + * + * @covers ::getUserCompetency + */ + public function testGetUserCompetencyNew(): void { + $query = $this->createMock('\Drupal\Core\Entity\Query\QueryInterface'); + $query->expects($this->once()) + ->method('condition') + ->with('user_id', 1) + ->willReturnSelf(); + $query->expects($this->once()) + ->method('accessCheck') + ->with(FALSE) + ->willReturnSelf(); + $query->expects($this->once()) + ->method('execute') + ->willReturn([]); + + $role_storage = $this->createMock('\Drupal\Core\Entity\EntityStorageInterface'); + + $storage = $this->createMock('\Drupal\Core\Entity\EntityStorageInterface'); + $storage->expects($this->once()) + ->method('getQuery') + ->willReturn($query); + $storage->expects($this->once()) + ->method('create') + ->with(['user_id' => 1]) + ->willReturn('competency'); + + $this->entityTypeManager->expects($this->exactly(2)) + ->method('getStorage') + ->willReturnMap([ + ['knowledge_competency', $storage], + ['user_role', $role_storage], + ]); + + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + $this->assertEquals('competency', $service->getUserCompetency(1)); + } + + /** + * Test getUserCompetency method. + * + * @covers ::getUserCompetency + */ + public function testGetUserCompetencyExisting(): void { + $query = $this->createMock('\Drupal\Core\Entity\Query\QueryInterface'); + $query->expects($this->once()) + ->method('condition') + ->with('user_id', 1) + ->willReturnSelf(); + $query->expects($this->once()) + ->method('accessCheck') + ->with(FALSE) + ->willReturnSelf(); + $query->expects($this->once()) + ->method('execute') + ->willReturn([1]); + $role_storage = $this->createMock('\Drupal\Core\Entity\EntityStorageInterface'); + + $storage = $this->createMock('\Drupal\Core\Entity\EntityStorageInterface'); + $storage->expects($this->once()) + ->method('getQuery') + ->willReturn($query); + $storage->expects($this->once()) + ->method('load') + ->with(1) + ->willReturn('competency'); + + $this->entityTypeManager->expects($this->exactly(2)) + ->method('getStorage') + ->willReturnMap([ + ['knowledge_competency', $storage], + ['user_role', $role_storage], + ]); + + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + $this->assertEquals('competency', $service->getUserCompetency(1)); + } + + /** + * Tests doRoleRemoval method. + * + * @covers ::doRoleRemoval + * @covers ::getRemovableRoles + */ + public function testDoRoleRemoval(): void { + $config = $this->createMock('\Drupal\Core\Config\ImmutableConfig'); + $config->expects($this->once()) + ->method('get') + ->with('roles') + ->willReturn([ + [ + 'role' => 'knowledge_contributor', + 'weight' => 1, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_publisher', + 'weight' => 2, + 'action' => 'auto', + 'promote' => 'self', + ], + [ + 'role' => 'knowledge_canidate', + 'weight' => 0, + 'action' => 'auto', + 'promote' => 'self', + ], + ]); + + $this->configFactory->expects($this->once()) + ->method('get') + ->with('knowledge.competency.settings') + ->willReturn($config); + + $service = new CompetencyService($this->configFactory, $this->entityTypeManager, $this->stringTranslation, $this->messenger); + $user = $this->createMock('\Drupal\user\UserInterface'); + $user->expects($this->once()) + ->method('getRoles') + ->willReturn(['knowledge_contributor', 'knowledge_publisher']); + + $service->doRoleRemoval($user); + } + +}