diff --git a/.docksal/docksal.env b/.docksal/docksal.env index 948007f53..7da5888bd 100644 --- a/.docksal/docksal.env +++ b/.docksal/docksal.env @@ -1,4 +1,4 @@ DOCKSAL_STACK=default DOCROOT=html -DB_IMAGE="docksal/db:1.1-mysql-5.7" +DB_IMAGE="docksal/mariadb:10.6" CLI_IMAGE='docksal/cli:php8.2-build' diff --git a/composer.lock b/composer.lock index 3d7361476..530352bae 100644 --- a/composer.lock +++ b/composer.lock @@ -118,16 +118,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.303.2", + "version": "3.304.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "c087819351de027791d830ffc7f45195488ae988" + "reference": "2435079c3e1a08148d955de15ec090018114f35a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c087819351de027791d830ffc7f45195488ae988", - "reference": "c087819351de027791d830ffc7f45195488ae988", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2435079c3e1a08148d955de15ec090018114f35a", + "reference": "2435079c3e1a08148d955de15ec090018114f35a", "shasum": "" }, "require": { @@ -207,9 +207,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.303.2" + "source": "https://github.com/aws/aws-sdk-php/tree/3.304.2" }, - "time": "2024-04-03T18:08:21+00:00" + "time": "2024-04-10T18:05:32+00:00" }, { "name": "behat/mink", @@ -1331,25 +1331,25 @@ }, { "name": "consolidation/annotated-command", - "version": "4.9.2", + "version": "4.10.0", "source": { "type": "git", "url": "https://github.com/consolidation/annotated-command.git", - "reference": "b5255dcbee1de95036185062a103dabc622224de" + "reference": "1e830ba908c9ffb1ba7ca056203531b27188812c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/b5255dcbee1de95036185062a103dabc622224de", - "reference": "b5255dcbee1de95036185062a103dabc622224de", + "url": "https://api.github.com/repos/consolidation/annotated-command/zipball/1e830ba908c9ffb1ba7ca056203531b27188812c", + "reference": "1e830ba908c9ffb1ba7ca056203531b27188812c", "shasum": "" }, "require": { "consolidation/output-formatters": "^4.3.1", "php": ">=7.1.3", "psr/log": "^1 || ^2 || ^3", - "symfony/console": "^4.4.8 || ^5 || ^6", - "symfony/event-dispatcher": "^4.4.8 || ^5 || ^6", - "symfony/finder": "^4.4.8 || ^5 || ^6" + "symfony/console": "^4.4.8 || ^5 || ^6 || ^7", + "symfony/event-dispatcher": "^4.4.8 || ^5 || ^6 || ^7", + "symfony/finder": "^4.4.8 || ^5 || ^6 || ^7" }, "require-dev": { "composer-runtime-api": "^2.0", @@ -1381,9 +1381,9 @@ "description": "Initialize Symfony Console commands from annotated command class methods.", "support": { "issues": "https://github.com/consolidation/annotated-command/issues", - "source": "https://github.com/consolidation/annotated-command/tree/4.9.2" + "source": "https://github.com/consolidation/annotated-command/tree/4.10.0" }, - "time": "2023-12-26T14:30:50+00:00" + "time": "2024-04-05T21:05:39+00:00" }, { "name": "consolidation/config", @@ -1497,32 +1497,32 @@ }, { "name": "consolidation/log", - "version": "3.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/consolidation/log.git", - "reference": "caaad9d70dae54eb49002666f000e3c607066878" + "reference": "c27a3beb36137c141ccbce0d89f64befb243c015" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/log/zipball/caaad9d70dae54eb49002666f000e3c607066878", - "reference": "caaad9d70dae54eb49002666f000e3c607066878", + "url": "https://api.github.com/repos/consolidation/log/zipball/c27a3beb36137c141ccbce0d89f64befb243c015", + "reference": "c27a3beb36137c141ccbce0d89f64befb243c015", "shasum": "" }, "require": { "php": ">=8.0.0", "psr/log": "^3", - "symfony/console": "^5 || ^6" + "symfony/console": "^5 || ^6 || ^7" }, "require-dev": { - "phpunit/phpunit": ">=7.5.20", + "phpunit/phpunit": "^7.5.20 || ^8 || ^9", "squizlabs/php_codesniffer": "^3", "yoast/phpunit-polyfills": "^0.2.0" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "2.x-dev" + "platform": { + "php": "8.2.17" } }, "autoload": { @@ -1543,9 +1543,9 @@ "description": "Improved Psr-3 / Psr\\Log logger based on Symfony Console components.", "support": { "issues": "https://github.com/consolidation/log/issues", - "source": "https://github.com/consolidation/log/tree/3.0.0" + "source": "https://github.com/consolidation/log/tree/3.1.0" }, - "time": "2022-04-05T16:53:32+00:00" + "time": "2024-04-04T23:50:25+00:00" }, { "name": "consolidation/output-formatters", @@ -1731,23 +1731,23 @@ }, { "name": "consolidation/site-alias", - "version": "4.0.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/consolidation/site-alias.git", - "reference": "b0eeb8c8f3d54d072824ee31b5e00cb5181f91c5" + "reference": "1056ceb93f6aafe6f7600d7bbe1b62b8488abccf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/site-alias/zipball/b0eeb8c8f3d54d072824ee31b5e00cb5181f91c5", - "reference": "b0eeb8c8f3d54d072824ee31b5e00cb5181f91c5", + "url": "https://api.github.com/repos/consolidation/site-alias/zipball/1056ceb93f6aafe6f7600d7bbe1b62b8488abccf", + "reference": "1056ceb93f6aafe6f7600d7bbe1b62b8488abccf", "shasum": "" }, "require": { - "consolidation/config": "^1.2.1 || ^2", + "consolidation/config": "^1.2.1 || ^2 || ^3", "php": ">=7.4", - "symfony/filesystem": "^5.4 || ^6", - "symfony/finder": "^5 || ^6" + "symfony/filesystem": "^5.4 || ^6 || ^7", + "symfony/finder": "^5 || ^6 || ^7" }, "require-dev": { "php-coveralls/php-coveralls": "^2.4.2", @@ -1784,30 +1784,30 @@ "description": "Manage alias records for local and remote sites.", "support": { "issues": "https://github.com/consolidation/site-alias/issues", - "source": "https://github.com/consolidation/site-alias/tree/4.0.1" + "source": "https://github.com/consolidation/site-alias/tree/4.1.0" }, - "time": "2023-04-29T17:18:10+00:00" + "time": "2024-04-05T15:58:04+00:00" }, { "name": "consolidation/site-process", - "version": "5.3.0", + "version": "5.4.0", "source": { "type": "git", "url": "https://github.com/consolidation/site-process.git", - "reference": "5e8eff50fd0015e7ca0b6ce4082cacef012f2f77" + "reference": "7ab3ffe4195a89b8dc334ea22e7881abe79ffd9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/consolidation/site-process/zipball/5e8eff50fd0015e7ca0b6ce4082cacef012f2f77", - "reference": "5e8eff50fd0015e7ca0b6ce4082cacef012f2f77", + "url": "https://api.github.com/repos/consolidation/site-process/zipball/7ab3ffe4195a89b8dc334ea22e7881abe79ffd9a", + "reference": "7ab3ffe4195a89b8dc334ea22e7881abe79ffd9a", "shasum": "" }, "require": { - "consolidation/config": "^2", + "consolidation/config": "^2 || ^3", "consolidation/site-alias": "^3 || ^4", "php": ">=8.0.14", - "symfony/console": "^5.4 || ^6", - "symfony/process": "^6" + "symfony/console": "^5.4 || ^6 || ^7", + "symfony/process": "^6 || ^7" }, "require-dev": { "phpunit/phpunit": "^9", @@ -1841,9 +1841,9 @@ "description": "A thin wrapper around the Symfony Process Component that allows applications to use the Site Alias library to specify the target for a remote call.", "support": { "issues": "https://github.com/consolidation/site-process/issues", - "source": "https://github.com/consolidation/site-process/tree/5.3.0" + "source": "https://github.com/consolidation/site-process/tree/5.4.0" }, - "time": "2024-04-01T12:42:12+00:00" + "time": "2024-04-06T00:00:28+00:00" }, { "name": "cweagans/composer-patches", @@ -5341,33 +5341,29 @@ }, { "name": "fileeye/mimemap", - "version": "2.0.3", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/FileEye/MimeMap.git", - "reference": "0795b7db12838ffb7bc564e0a02cf53fb1463ec0" + "reference": "4ea9ac8d7fc599fffe7108f8821a7b324b5d0af4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FileEye/MimeMap/zipball/0795b7db12838ffb7bc564e0a02cf53fb1463ec0", - "reference": "0795b7db12838ffb7bc564e0a02cf53fb1463ec0", + "url": "https://api.github.com/repos/FileEye/MimeMap/zipball/4ea9ac8d7fc599fffe7108f8821a7b324b5d0af4", + "reference": "4ea9ac8d7fc599fffe7108f8821a7b324b5d0af4", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.4" }, "require-dev": { "composer-runtime-api": "^2.0.0", - "phpstan/phpstan": "^1.2", - "phpunit/phpunit": "^9 | ^10", "sebastian/comparator": ">=4", "sebastian/diff": ">=4", - "squizlabs/php_codesniffer": ">=3.6", "symfony/console": ">=5.4", "symfony/filesystem": ">=5.4", "symfony/var-dumper": ">=5.4", - "symfony/yaml": ">=5.4", - "vimeo/psalm": "^4.23 | ^5" + "symfony/yaml": ">=5.4" }, "bin": [ "bin/fileeye-mimemap" @@ -5397,9 +5393,9 @@ ], "support": { "issues": "https://github.com/FileEye/MimeMap/issues", - "source": "https://github.com/FileEye/MimeMap/tree/2.0.3" + "source": "https://github.com/FileEye/MimeMap/tree/2.1.0" }, - "time": "2023-11-11T14:14:23+00:00" + "time": "2024-04-06T13:00:52+00:00" }, { "name": "fileeye/pel", @@ -10109,16 +10105,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.18", + "version": "9.6.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "32c2c2d6580b1d8ab3c10b1e9e4dc263cc69bb04" + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/32c2c2d6580b1d8ab3c10b1e9e4dc263cc69bb04", - "reference": "32c2c2d6580b1d8ab3c10b1e9e4dc263cc69bb04", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8", + "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8", "shasum": "" }, "require": { @@ -10192,7 +10188,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.18" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19" }, "funding": [ { @@ -10208,7 +10204,7 @@ "type": "tidelift" } ], - "time": "2024-03-21T12:07:32+00:00" + "time": "2024-04-05T04:35:58+00:00" }, { "name": "psr/cache", @@ -15811,16 +15807,16 @@ }, { "name": "unocha/gtm_barebones", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/UN-OCHA/gtm_barebones.git", - "reference": "fe2ed59384bf8e8575c83c9a30abab08e53180db" + "reference": "80f58df7e9169d531bd840f0ecbcc72184d19bf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/UN-OCHA/gtm_barebones/zipball/fe2ed59384bf8e8575c83c9a30abab08e53180db", - "reference": "fe2ed59384bf8e8575c83c9a30abab08e53180db", + "url": "https://api.github.com/repos/UN-OCHA/gtm_barebones/zipball/80f58df7e9169d531bd840f0ecbcc72184d19bf6", + "reference": "80f58df7e9169d531bd840f0ecbcc72184d19bf6", "shasum": "" }, "require": { @@ -15832,9 +15828,9 @@ "description": "OCHA fork of GTM Barebones.", "support": { "issues": "https://github.com/UN-OCHA/gtm_barebones/issues", - "source": "https://github.com/UN-OCHA/gtm_barebones/tree/1.1.1" + "source": "https://github.com/UN-OCHA/gtm_barebones/tree/1.1.2" }, - "time": "2024-02-16T11:12:44+00:00" + "time": "2024-04-12T06:49:31+00:00" }, { "name": "unocha/ocha_ai", diff --git a/config/core.entity_form_display.node.job.default.yml b/config/core.entity_form_display.node.job.default.yml index bcca5d6df..41d1c5c66 100644 --- a/config/core.entity_form_display.node.job.default.yml +++ b/config/core.entity_form_display.node.job.default.yml @@ -15,6 +15,8 @@ dependencies: - field.field.node.job.field_job_type - field.field.node.job.field_source - field.field.node.job.field_theme + - field.field.node.job.reliefweb_job_tagger_info + - field.field.node.job.reliefweb_job_tagger_status - node.type.job module: - allowed_formats @@ -189,6 +191,8 @@ hidden: field_import_hash: true langcode: true promote: true + reliefweb_job_tagger_info: true + reliefweb_job_tagger_status: true status: true sticky: true uid: true diff --git a/config/core.entity_view_display.node.job.default.yml b/config/core.entity_view_display.node.job.default.yml index 3af4adf88..0dc4ef174 100644 --- a/config/core.entity_view_display.node.job.default.yml +++ b/config/core.entity_view_display.node.job.default.yml @@ -15,6 +15,8 @@ dependencies: - field.field.node.job.field_job_type - field.field.node.job.field_source - field.field.node.job.field_theme + - field.field.node.job.reliefweb_job_tagger_info + - field.field.node.job.reliefweb_job_tagger_status - node.type.job module: - datetime @@ -114,3 +116,5 @@ hidden: field_import_hash: true langcode: true links: true + reliefweb_job_tagger_info: true + reliefweb_job_tagger_status: true diff --git a/config/core.entity_view_display.node.job.teaser.yml b/config/core.entity_view_display.node.job.teaser.yml index 764868069..bb4714591 100644 --- a/config/core.entity_view_display.node.job.teaser.yml +++ b/config/core.entity_view_display.node.job.teaser.yml @@ -16,6 +16,8 @@ dependencies: - field.field.node.job.field_job_type - field.field.node.job.field_source - field.field.node.job.field_theme + - field.field.node.job.reliefweb_job_tagger_info + - field.field.node.job.reliefweb_job_tagger_status - node.type.job module: - datetime @@ -60,3 +62,5 @@ hidden: field_theme: true langcode: true links: true + reliefweb_job_tagger_info: true + reliefweb_job_tagger_status: true diff --git a/config/core.extension.yml b/config/core.extension.yml index cf33cf061..af50f6ee4 100644 --- a/config/core.extension.yml +++ b/config/core.extension.yml @@ -53,6 +53,7 @@ module: node: 0 ocha_ai: 0 ocha_ai_chat: 0 + ocha_ai_tag: 0 ocha_monitoring: 0 options: 0 page_cache: 0 @@ -72,6 +73,7 @@ module: reliefweb_guidelines: 0 reliefweb_homepage: 0 reliefweb_import: 0 + reliefweb_job_tagger: 0 reliefweb_meta: 0 reliefweb_moderation: 0 reliefweb_reporting: 0 diff --git a/config/field.field.node.job.field_career_categories.yml b/config/field.field.node.job.field_career_categories.yml index 12fb8f3f8..baa44e0fd 100644 --- a/config/field.field.node.job.field_career_categories.yml +++ b/config/field.field.node.job.field_career_categories.yml @@ -12,7 +12,7 @@ entity_type: node bundle: job label: 'Career categories' description: '' -required: true +required: false translatable: false default_value: { } default_value_callback: '' @@ -23,7 +23,7 @@ settings: career_category: career_category sort: field: name - direction: asc - auto_create: false + direction: ASC + auto_create: 0 auto_create_bundle: '' field_type: entity_reference diff --git a/config/field.field.node.job.field_job_experience.yml b/config/field.field.node.job.field_job_experience.yml index 470d80936..d8ac98a69 100644 --- a/config/field.field.node.job.field_job_experience.yml +++ b/config/field.field.node.job.field_job_experience.yml @@ -23,7 +23,7 @@ settings: job_experience: job_experience sort: field: name - direction: asc - auto_create: false + direction: ASC + auto_create: 0 auto_create_bundle: '' field_type: entity_reference diff --git a/config/field.field.node.job.reliefweb_job_tagger_info.yml b/config/field.field.node.job.reliefweb_job_tagger_info.yml new file mode 100644 index 000000000..4b73a7226 --- /dev/null +++ b/config/field.field.node.job.reliefweb_job_tagger_info.yml @@ -0,0 +1,26 @@ +uuid: bf072428-5463-444c-aa3b-5867c18e5820 +langcode: en +status: true +dependencies: + config: + - field.storage.node.reliefweb_job_tagger_info + - filter.format.markdown + - node.type.job + module: + - text +_core: + default_config_hash: c9jZ6pByZz5O4j5rz8-PTwZpIhgpD5B9vRSD6y2KaL4 +id: node.job.reliefweb_job_tagger_info +field_name: reliefweb_job_tagger_info +entity_type: node +bundle: job +label: 'Job tagger info' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + allowed_formats: + - markdown +field_type: text_long diff --git a/config/field.field.node.job.reliefweb_job_tagger_status.yml b/config/field.field.node.job.reliefweb_job_tagger_status.yml new file mode 100644 index 000000000..baf6fd85c --- /dev/null +++ b/config/field.field.node.job.reliefweb_job_tagger_status.yml @@ -0,0 +1,23 @@ +uuid: 1e084105-9ae6-435a-8c64-428e9957508e +langcode: en +status: true +dependencies: + config: + - field.storage.node.reliefweb_job_tagger_status + - node.type.job + module: + - options +_core: + default_config_hash: b39BL7pzxGe8ARXfSfgWQ56VdVlrzDeu5QPN0V6FB6U +id: node.job.reliefweb_job_tagger_status +field_name: reliefweb_job_tagger_status +entity_type: node +bundle: job +label: 'Job tagger state' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: list_string diff --git a/config/field.storage.node.reliefweb_job_tagger_info.yml b/config/field.storage.node.reliefweb_job_tagger_info.yml new file mode 100644 index 000000000..b8b542637 --- /dev/null +++ b/config/field.storage.node.reliefweb_job_tagger_info.yml @@ -0,0 +1,21 @@ +uuid: c9d57c46-67fe-4662-a647-cbc139b8b5ab +langcode: en +status: true +dependencies: + module: + - node + - text +_core: + default_config_hash: unTujV1MU9BLJ6YJTAJP79UzayOJZqe3ENIunYL_eoU +id: node.reliefweb_job_tagger_info +field_name: reliefweb_job_tagger_info +entity_type: node +type: text_long +settings: { } +module: text +locked: true +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/field.storage.node.reliefweb_job_tagger_status.yml b/config/field.storage.node.reliefweb_job_tagger_status.yml new file mode 100644 index 000000000..c0af98840 --- /dev/null +++ b/config/field.storage.node.reliefweb_job_tagger_status.yml @@ -0,0 +1,32 @@ +uuid: eff4e934-a8c8-4c26-87dd-3e86f9311a78 +langcode: en +status: true +dependencies: + module: + - node + - options +_core: + default_config_hash: bGdwPWYjAlDGCrUl508wL_rTVtBV2UWW1UJtbe5PFB8 +id: node.reliefweb_job_tagger_status +field_name: reliefweb_job_tagger_status +entity_type: node +type: list_string +settings: + allowed_values: + - + value: queue + label: queue + - + value: queued + label: queued + - + value: processed + label: processed + allowed_values_function: '' +module: options +locked: true +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/config/ocha_ai_tag.settings.yml b/config/ocha_ai_tag.settings.yml new file mode 100644 index 000000000..4e33a6e94 --- /dev/null +++ b/config/ocha_ai_tag.settings.yml @@ -0,0 +1,21 @@ +_core: + default_config_hash: r1hk7e31MjYWgy4AuBRXxwuhornPFBp0LDrncwSG38Q +defaults: + form: + instructions: + value: 'The process of posting jobs via ReliefWeb is now even smoother. The form now includes an automated function for the "career" and "themes" categories; fewer fields for users to fill and higher efficiency overall.' + format: markdown_editor + plugins: + completion: + plugin_id: aws_bedrock + embedding: + plugin_id: aws_bedrock + source: + plugin_id: reliefweb + text_extractor: + application/pdf: + plugin_id: mupdf + text_splitter: + plugin_id: token + vector_store: + plugin_id: elasticsearch diff --git a/config/user.role.authenticated.yml b/config/user.role.authenticated.yml index ffcd01c9f..febea45f6 100644 --- a/config/user.role.authenticated.yml +++ b/config/user.role.authenticated.yml @@ -15,6 +15,7 @@ dependencies: - node - reliefweb_bookmarks - reliefweb_form + - reliefweb_job_tagger - reliefweb_moderation - reliefweb_subscriptions - reliefweb_user_posts @@ -35,6 +36,7 @@ permissions: - 'delete own training content' - 'edit own job content' - 'edit own training content' + - 'enforce ocha ai job tag' - 'manage own subscriptions' - 'use enhanced input forms' - 'use text format markdown' diff --git a/config/user.role.editor.yml b/config/user.role.editor.yml index e31d87a45..58ddfc54a 100644 --- a/config/user.role.editor.yml +++ b/config/user.role.editor.yml @@ -36,6 +36,7 @@ dependencies: - reliefweb_form - reliefweb_guidelines - reliefweb_homepage + - reliefweb_job_tagger - reliefweb_moderation - reliefweb_revisions - reliefweb_topics @@ -63,6 +64,7 @@ permissions: - 'administer community topics' - 'administer url aliases' - 'archive content' + - 'bypass ocha ai job tag' - 'create announcement content' - 'create blog_post content' - 'create book content' diff --git a/config/user.role.user_manager.yml b/config/user.role.user_manager.yml index 247d3393a..48b66cc2e 100644 --- a/config/user.role.user_manager.yml +++ b/config/user.role.user_manager.yml @@ -3,6 +3,7 @@ langcode: en status: true dependencies: module: + - reliefweb_job_tagger - reliefweb_subscriptions - reliefweb_users - system @@ -21,6 +22,7 @@ permissions: - 'assign job_importer role' - 'assign user_manager role' - 'assign webmaster role' + - 'bypass ocha ai job tag' - 'change own username' - 'manage user roles' - 'view reliefweb admin menu' diff --git a/config/user.role.webmaster.yml b/config/user.role.webmaster.yml index d7bf681e2..d9aceae06 100644 --- a/config/user.role.webmaster.yml +++ b/config/user.role.webmaster.yml @@ -29,6 +29,7 @@ dependencies: - ocha_ai_chat - reliefweb_bookmarks - reliefweb_guidelines + - reliefweb_job_tagger - reliefweb_users - system - taxonomy @@ -44,6 +45,7 @@ permissions: - 'access taxonomy overview' - 'add content to books' - 'add guideline entities' + - 'bypass ocha ai job tag' - 'create new books' - 'create terms in career_category' - 'create terms in content_format' diff --git a/html/modules/custom/reliefweb_job_tagger/components/ai-message/ai-message.css b/html/modules/custom/reliefweb_job_tagger/components/ai-message/ai-message.css new file mode 100644 index 000000000..680525735 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/components/ai-message/ai-message.css @@ -0,0 +1,21 @@ +.ai-message-wrapper { + border-bottom: 0 !important; + padding-bottom: 0 !important; + padding-left: 32px !important; +} + +@media screen and (min-width: 767px) { + .ai-message-wrapper { + padding-left: 40px !important; + } +} + +.ai-message-wrapper legend { + display: none; + margin: 0; + padding: 0; +} + +[required] .js-form-type-radio:has(input[value="_none"]) { + display: none !important; +} diff --git a/html/modules/custom/reliefweb_job_tagger/config/install/field.field.node.job.reliefweb_job_tagger_info.yml b/html/modules/custom/reliefweb_job_tagger/config/install/field.field.node.job.reliefweb_job_tagger_info.yml new file mode 100644 index 000000000..140f89921 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/config/install/field.field.node.job.reliefweb_job_tagger_info.yml @@ -0,0 +1,23 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.reliefweb_job_tagger_info + - filter.format.markdown + - node.type.job + module: + - text +id: node.job.reliefweb_job_tagger_info +field_name: reliefweb_job_tagger_info +entity_type: node +bundle: job +label: 'Job tagger info' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + allowed_formats: + - markdown +field_type: text_long diff --git a/html/modules/custom/reliefweb_job_tagger/config/install/field.field.node.job.reliefweb_job_tagger_status.yml b/html/modules/custom/reliefweb_job_tagger/config/install/field.field.node.job.reliefweb_job_tagger_status.yml new file mode 100644 index 000000000..f3ddba0cf --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/config/install/field.field.node.job.reliefweb_job_tagger_status.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.reliefweb_job_tagger_status + - node.type.job + module: + - options +id: node.job.reliefweb_job_tagger_status +field_name: reliefweb_job_tagger_status +entity_type: node +bundle: job +label: 'Job tagger state' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: { } +field_type: list_string diff --git a/html/modules/custom/reliefweb_job_tagger/config/install/field.storage.node.reliefweb_job_tagger_info.yml b/html/modules/custom/reliefweb_job_tagger/config/install/field.storage.node.reliefweb_job_tagger_info.yml new file mode 100644 index 000000000..bb13375f1 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/config/install/field.storage.node.reliefweb_job_tagger_info.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + module: + - node + - text +id: node.reliefweb_job_tagger_info +field_name: reliefweb_job_tagger_info +entity_type: node +type: text_long +settings: { } +module: text +locked: true +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/html/modules/custom/reliefweb_job_tagger/config/install/field.storage.node.reliefweb_job_tagger_status.yml b/html/modules/custom/reliefweb_job_tagger/config/install/field.storage.node.reliefweb_job_tagger_status.yml new file mode 100644 index 000000000..f18e3c5a1 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/config/install/field.storage.node.reliefweb_job_tagger_status.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + module: + - node + - options +id: node.reliefweb_job_tagger_status +field_name: reliefweb_job_tagger_status +entity_type: node +type: list_string +settings: + allowed_values: + - + value: queue + label: queue + - + value: queued + label: queued + - + value: processed + label: processed + allowed_values_function: '' +module: options +locked: true +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.info.yml b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.info.yml new file mode 100644 index 000000000..2c660c57c --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.info.yml @@ -0,0 +1,9 @@ +type: module +name: ReliefWeb OCHA AI Job Tagger +description: 'OCHA AI Job Tagger for reliefweb.' +package: reliefweb +core_version_requirement: ^9 || ^10 +dependencies: + - drupal:ocha_ai_tag + - drupal:reliefweb_moderation + - drupal:reliefweb_utility diff --git a/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.libraries.yml b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.libraries.yml new file mode 100644 index 000000000..3fb6d44c2 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.libraries.yml @@ -0,0 +1,4 @@ +ai-message: + css: + theme: + components/ai-message/ai-message.css: {} diff --git a/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.module b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.module new file mode 100644 index 000000000..1795da5e0 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.module @@ -0,0 +1,295 @@ +getFormObject()->getEntity(); + + if (UserHelper::userHasRoles(['editor'])) { + if ($entity->hasField('reliefweb_job_tagger_info') && !$entity->reliefweb_job_tagger_info->IsEmpty()) { + $message = $entity->reliefweb_job_tagger_info->value; + + $form['ai_feedback'] = [ + '#type' => 'processed_text', + '#text' => $message, + '#format' => 'html', + '#weight' => -90, + ]; + } + } + + // Skip when editing a job that already has a career category that was not + // added via the AI. + // That includes all the jobs before the deployment of the AI tagging since + // the career category field is mandatory. + $skip = !$entity->get('field_career_categories')->isEmpty() && + $entity->get('reliefweb_job_tagger_status')->isEmpty(); + } + + // Check permissions. + $user = \Drupal::currentUser(); + if ($user->hasPermission('bypass ocha ai job tag')) { + $skip = TRUE; + } + + if (!$user->hasPermission('enforce ocha ai job tag')) { + $skip = TRUE; + } + + if ($skip) { + // Ensure the field is mandatory because we cannot do that at the field + // definition level. It indeed needs to be optional so that it can be + // ignored when it is to be filled by the AI. + $form['field_career_categories']['widget']['#required'] = TRUE; + + return; + } + + // Add a validation callback so we can check if the career categories field + // is set for trusted users who selected a source they are trusted for. + $form['#validate'][] = 'reliefweb_job_tagger_validate_mandatory_fields'; + + $settings = \Drupal::service('ocha_ai_tag.tagger')->getSettings(); + + if (!empty($settings['form']['instructions']['value'])) { + // Add message for job posters. + $form['ai_message'] = [ + '#type' => 'fieldset', + '#attached' => [ + 'library' => [ + 'reliefweb_job_tagger/ai-message', + ], + ], + '#attributes' => [ + 'class' => [ + 'ai-message-wrapper', + ], + ], + 'message' => [ + '#type' => 'processed_text', + '#text' => $settings['form']['instructions']['value'], + '#format' => $settings['form']['instructions']['format'] ?? 'html', + '#weight' => -90, + '#prefix' => '
', + '#states' => [], + ], + ]; + } + + $sources = reliefweb_job_tagger_get_trusted_organizations($user); + if (empty($sources)) { + // Non-trusted poster, hide fields. + $form['field_career_categories']['#access'] = FALSE; + $form['field_theme']['#access'] = FALSE; + + return; + } + + // Show and mark fields mandatory for trusted sources. + $fields = [ + 'field_career_categories' => 'required', + 'field_theme' => 'optional', + ]; + + $conditions = []; + foreach ($sources as $source) { + $conditions[] = [ + 'value' => $source, + ]; + } + + foreach ($fields as $field => $needed) { + if ($needed == 'required') { + $form[$field]['#states'] = [ + 'visible' => [ + 'select[name="field_source"]' => $conditions, + ], + 'required' => [ + 'select[name="field_source"]' => $conditions, + ], + ]; + } + else { + $form[$field]['#states'] = [ + 'visible' => [ + 'select[name="field_source"]' => $conditions, + ], + ]; + } + } + + $form['ai_message']['#states'] = [ + 'invisible' => [ + 'select[name="field_source"]' => $conditions, + ], + ]; +} + +/** + * Get a list of trusted sources for a given account. + */ +function reliefweb_job_tagger_get_trusted_organizations($account = NULL) { + $sources = UserPostingRightsHelper::getUserPostingRights($account); + $sources = array_filter($sources, function ($info) { + if (isset($info['job']) && $info['job'] == 3) { + return TRUE; + } + }); + $sources = array_keys($sources); + + return $sources; +} + +/** + * Validate mandatory fields. + */ +function reliefweb_job_tagger_validate_mandatory_fields($form, FormStateInterface $form_state) { + $trusted_sources = reliefweb_job_tagger_get_trusted_organizations(); + $source = $form_state->getValue(['field_source', 0, 'target_id']); + + // If the selected source is a trusted source, then the career category field + // is mandatory since it will not be processed by the AI. + // + // @see reliefweb_job_tagger_form_node_form_alter(). + if (!empty($trusted_sources) && !empty($source) && in_array($source, $trusted_sources)) { + // Check if a career category was selected. + if (!$form_state->hasValue(['field_career_categories', 0, 'target_id'])) { + $form_state->setError($form['field_career_categories']['widget'], t('@name field is required.', [ + '@name' => $form['field_career_categories']['widget']['#title'], + ])); + } + } +} + +/** + * Implements hook_module_implements_alter(). + */ +function reliefweb_job_tagger_module_implements_alter(&$implementations, $hook) { + switch ($hook) { + // Move our hook_entity_type_alter() implementation to the end of the list. + case 'node_presave': + $group = $implementations['reliefweb_job_tagger']; + unset($implementations['reliefweb_job_tagger']); + $implementations['reliefweb_job_tagger'] = $group; + break; + } +} + +/** + * Implements hook_ENTITY_TYPE_presave(). + */ +function reliefweb_job_tagger_node_presave(EntityInterface $node) { + // We don't want to react to configuration imports. + if (\Drupal::isConfigSyncing()) { + return; + } + + if (!$node instanceof Node) { + return; + } + + if ($node->bundle() != 'job') { + return; + } + + // Skip queued and processed nodes. + if ($node->hasField('reliefweb_job_tagger_status')) { + if ($node->reliefweb_job_tagger_status->value == 'queued' || $node->reliefweb_job_tagger_status->value == 'processed') { + return; + } + } + + if ($node->moderation_status->value != 'pending') { + $node->set('reliefweb_job_tagger_status', ''); + return; + } + + // Check permissions. + $user = \Drupal::currentUser(); + if ($user->hasPermission('bypass ocha ai job tag')) { + return; + } + + if (!$user->hasPermission('enforce ocha ai job tag')) { + return; + } + + // Only queue it when fields are empty. + if (!$node->field_career_categories->isEmpty()) { + return; + } + + if (!$node->field_theme->isEmpty()) { + return; + } + + // Queue node when status is empty. + if ($node->reliefweb_job_tagger_status->isEmpty()) { + $node->set('reliefweb_job_tagger_status', 'queued'); + + $log_message = $node->getRevisionLogMessage(); + $log_message .= (empty($log_message) ? '' : ' ') . 'Job has been queued for tagging.'; + $node->setRevisionLogMessage($log_message); + } +} + +/** + * Implements hook_entity_after_save(). + * + * @see \Drupal\reliefweb_entities\BundleEntityStorageInterface + */ +function reliefweb_job_tagger_entity_after_save(EntityInterface $entity) { + // We don't want to react to configuration imports. + if (\Drupal::isConfigSyncing()) { + return; + } + + $entity_type_id = $entity->getEntityTypeId(); + + if ($entity_type_id !== 'node') { + return; + } + + /** @var \Drupal\node\Entity\Node $entity */ + if ($entity->hasField('reliefweb_job_tagger_status') && $entity->get('reliefweb_job_tagger_status')->value == 'queued') { + reliefweb_job_tagger_queue_job($entity); + } +} + +/** + * Queue the job for tagging. + */ +function reliefweb_job_tagger_queue_job(Node $job) : void { + /** @var \Drupal\Core\Queue\QueueInterface $queue */ + $queue = \Drupal::service('queue')->get('reliefweb_job_tagger'); + + $item = new \stdClass(); + $item->nid = $job->id(); + $queue->createItem($item); +} diff --git a/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.permissions.yml b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.permissions.yml new file mode 100644 index 000000000..eb8371a20 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/reliefweb_job_tagger.permissions.yml @@ -0,0 +1,7 @@ +enforce ocha ai job tag: + title: 'Enforce OCHA AI Job tag' + description: 'Enforce the use of OCHA AI Job tag.' + +bypass ocha ai job tag: + title: 'Bypass OCHA AI Job tag' + description: 'Allow users to ignore Access OCHA AI Chat advanced features.' diff --git a/html/modules/custom/reliefweb_job_tagger/src/Plugin/QueueWorker/OchaAiJobTagTaggerWorker.php b/html/modules/custom/reliefweb_job_tagger/src/Plugin/QueueWorker/OchaAiJobTagTaggerWorker.php new file mode 100644 index 000000000..596391486 --- /dev/null +++ b/html/modules/custom/reliefweb_job_tagger/src/Plugin/QueueWorker/OchaAiJobTagTaggerWorker.php @@ -0,0 +1,250 @@ +entityTypeManager = $entity_type_manager; + $this->jobTagger = $job_tagger; + $this->logger = $logger_factory->get('reliefweb_job_tagger'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('entity_type.manager'), + $container->get('ocha_ai_tag.tagger'), + $container->get('logger.factory'), + ); + } + + /** + * {@inheritdoc} + */ + public function processItem($data) { + $nid = $data->nid; + + if (empty($nid)) { + $this->logger->warning('No nid specified, skipping'); + return; + } + + /** @var \Drupal\node\Entity\Node $node */ + $node = $this->entityTypeManager->getStorage('node')->load($nid); + + if (!$node || $node->bundle() !== 'job') { + $this->logger->warning('Unable to load job node @nid, skipping', ['@nid' => $nid]); + return; + } + + if ($node->hasField('reliefweb_job_tagger_status') && $node->reliefweb_job_tagger_status->value == 'processed') { + $this->logger->warning('Node @nid already processed, skipping', ['@nid' => $nid]); + return; + } + + if ($node->body->isEmpty()) { + $this->logger->warning('No body text present for node @nid, skipping', ['@nid' => $nid]); + return; + } + + // Only process it when fields are empty. + if (!$node->field_career_categories->isEmpty()) { + $this->logger->warning('Category already specified for node @nid, skipping', ['@nid' => $nid]); + return; + } + + if (!$node->field_theme->isEmpty()) { + $this->logger->warning('Theme(s) already specified for node @nid, skipping', ['@nid' => $nid]); + return; + } + + // Load vocabularies. + $mapping = []; + $term_cache_tags = []; + $vocabularies = [ + 'career_category', + 'theme', + ]; + foreach ($vocabularies as $vocabulary) { + $mapping[$vocabulary] = []; + $terms = $this->entityTypeManager->getStorage('taxonomy_term')->loadByProperties([ + 'status' => 1, + 'vid' => $vocabulary, + ]); + /** @var \Drupal\taxonomy\Entity\Term $term */ + foreach ($terms as $term) { + $mapping[$vocabulary][$term->getName()] = $term->getDescription() ?? $term->getName(); + $term_cache_tags = array_merge($term_cache_tags, $term->getCacheTags()); + } + } + + $text = $node->getTitle() . "\n\n" . $node->get('body')->value; + $data = $this->jobTagger + ->setVocabularies($mapping, $term_cache_tags) + ->tag($text, [OchaAiTagTagger::CALCULATION_METHOD_MEAN_WITH_CUTOFF], OchaAiTagTagger::AVERAGE_FULL_AVERAGE); + + if (empty($data)) { + $this->logger->error('No data received from AI for node @nid', ['@nid' => $nid]); + return; + } + + if (!isset($data[OchaAiTagTagger::AVERAGE_FULL_AVERAGE][OchaAiTagTagger::CALCULATION_METHOD_MEAN_WITH_CUTOFF])) { + $this->logger->error('Data "average mean with cutoff" missing from AI for node @nid', ['@nid' => $nid]); + return; + } + + // Use average mean with cutoff. + $data = $data[OchaAiTagTagger::AVERAGE_FULL_AVERAGE][OchaAiTagTagger::CALCULATION_METHOD_MEAN_WITH_CUTOFF]; + $message = []; + $needs_save = FALSE; + + if (isset($data['career_category']) && $node->field_career_categories->isEmpty()) { + $term = $this->getRelevantTerm('career_category', $data['career_category'], 1); + $message[] = $this->setAiFeedback('Career category', $data['career_category'], [$term]); + + $node->set('field_career_categories', $term); + $needs_save = TRUE; + } + + if (isset($data['theme']) && $node->field_theme->isEmpty()) { + $terms = $this->getRelevantTerm('theme', $data['theme'], 3); + $message[] = $this->setAiFeedback('Theme(s)', $data['theme'], $terms); + + $node->set('field_theme', $terms); + $needs_save = TRUE; + } + + if ($needs_save) { + if ($node->hasField('reliefweb_job_tagger_info')) { + $node->set('reliefweb_job_tagger_info', [ + 'value' => implode("\n\n", $message), + 'format' => 'markdown', + ]); + } + $node->setRevisionLogMessage('Job has been updated by AI.'); + $node->set('reliefweb_job_tagger_status', 'processed'); + $node->setNewRevision(TRUE); + $node->save(); + $this->logger->info('Node @nid updated with data from AI', ['@nid' => $nid]); + } + } + + /** + * Get top 3 relevant terms. + */ + protected function getTopNumTerms($terms, $limit) { + $result = []; + + $terms = array_slice($terms, 0, $limit, TRUE); + + foreach ($terms as $term => $score) { + // Add first one regardless of score. + if (empty($result)) { + $result[] = $term; + continue; + } + + if ($score > .25) { + $result[] = $term; + } + + } + + return $result; + } + + /** + * Get relevant terms. + */ + protected function getRelevantTerm($vocabulary, $data, $limit) { + $storage = $this->entityTypeManager->getStorage('taxonomy_term'); + + $items = $this->getTopNumTerms($data, $limit); + + $terms = $storage->loadByProperties([ + 'name' => $items, + 'vid' => $vocabulary, + ]); + + return $limit === 1 ? reset($terms) : $terms; + } + + /** + * Construct AI feedback message. + */ + protected function setAiFeedback($title, $data, $terms, $limit = 5) { + $message = []; + $message[] = '**' . $title . '**:' . "\n\n"; + + // Max 5 items. + $items = array_slice($data, 0, $limit); + + // Selected terms. + $selected = array_map( + function ($term) { + return $term->getName(); + }, + $terms, + ); + + foreach ($items as $key => $confidence) { + if (in_array($key, $selected)) { + $message[] = '- **' . $key . '**: ' . floor(100 * $confidence) . '%' . "\n"; + } + else { + $message[] = '- ' . $key . ': ' . floor(100 * $confidence) . '%' . "\n"; + } + } + + return implode('', $message); + } + +} diff --git a/html/modules/custom/reliefweb_key_figures/README.md b/html/modules/custom/reliefweb_key_figures/README.md deleted file mode 100644 index 0254b8d3c..000000000 --- a/html/modules/custom/reliefweb_key_figures/README.md +++ /dev/null @@ -1,12 +0,0 @@ -ReliefWeb - Key figures module -============================== - -This module provides integration with the ReliefWeb Key Figures API. - -## Client - -This module provides a client to perform request against the ReliefWeb Key Figures API via the [reliefweb_key_figures.client](src/Services/KeyFiguresClient) service. - -## Template - -This module provides a [template](src/templates/reliefweb-key-figures.html.twig) for the Key Figures. diff --git a/html/modules/custom/reliefweb_key_figures/config/install/reliefweb_key_figures.settings.yml b/html/modules/custom/reliefweb_key_figures/config/install/reliefweb_key_figures.settings.yml deleted file mode 100644 index c71773b51..000000000 --- a/html/modules/custom/reliefweb_key_figures/config/install/reliefweb_key_figures.settings.yml +++ /dev/null @@ -1,6 +0,0 @@ -# API URL for the key figures. -api_url: 'https://raw.githubusercontent.com/reliefweb/crisis-app-data/v2/edition/world/countries/' -# URL to the HDX page for the ReliefWeb key figures. -hdx_url: 'https://data.humdata.org/dataset/reliefweb-crisis-figures' -# Number of seconds to cache the data for. -cache_lifetime: 300 diff --git a/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.info.yml b/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.info.yml deleted file mode 100644 index eec47d827..000000000 --- a/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.info.yml +++ /dev/null @@ -1,5 +0,0 @@ -type: module -name: ReliefWeb Key Figures -description: 'Provides integration with the ReliefWeb Key Figures.' -package: reliefweb -core_version_requirement: ^9 || ^10 diff --git a/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.module b/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.module deleted file mode 100644 index ce2ded6f9..000000000 --- a/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.module +++ /dev/null @@ -1,47 +0,0 @@ - [ - 'variables' => [ - // Section heading level. - 'level' => 2, - // Section id. - 'id' => 'key-figures', - // Section attributes. - 'attributes' => NULL, - // Section title. - 'title' => t('Key figures'), - // Section title attributes. - 'title_attributes' => NULL, - // Language ISO 2 code of the figures. - 'langcode' => 'en', - // Name of the country the figures are for. - 'country' => '', - // List of figures. Each figure has the following properties: - // - status: standard or recent - // - name: figure label - // - value: figure value (number) - // - trand: if defined, has a message and since properties - // - sparkline: if defined, has a list of points - // - date: last update time - // - updated: formatted relative update date. - // - url: URL to the report the figures came from - // - source: short name of the source. - 'figures' => [], - // Indicates if there are more figures that can be shown. - 'more' => FALSE, - // If defined, has a url and title properties. - 'dataset' => NULL, - ], - ], - ]; -} diff --git a/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.services.yml b/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.services.yml deleted file mode 100644 index b94a29119..000000000 --- a/html/modules/custom/reliefweb_key_figures/reliefweb_key_figures.services.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - reliefweb_key_figures.client: - class: Drupal\reliefweb_key_figures\Services\KeyFiguresClient - arguments: ['@cache.default', '@config.factory', '@datetime.time', '@http_client', '@language_manager', '@logger.factory', '@request_stack', '@string_translation'] diff --git a/html/modules/custom/reliefweb_key_figures/src/Services/KeyFiguresClient.php b/html/modules/custom/reliefweb_key_figures/src/Services/KeyFiguresClient.php deleted file mode 100644 index 6aa476b5d..000000000 --- a/html/modules/custom/reliefweb_key_figures/src/Services/KeyFiguresClient.php +++ /dev/null @@ -1,162 +0,0 @@ -cache = $cache_backend; - $this->config = $config_factory->get('reliefweb_key_figures.settings'); - $this->time = $time; - $this->httpClient = $http_client; - $this->languageManager = $language_manager; - $this->requestStack = $request_stack; - $this->stringTranslation = $string_translation; - $this->logger = $logger_factory->get('reliefweb_key_figures'); - } - - /** - * Get the render array with the ReliefWeb key figures for the country. - * - * @param string $iso3 - * ISO3 code of the country for which to retrieve the key figures. - * @param string $country - * Country name. - * - * @return array - * Return the render array for the key figures for the country - * (empty if none was found). This render array has the following keys: - * - #theme: reliefweb_key_figures - * - #langcode: language iso 2 code - * - #country: name of the country the figures are for - * - #figures: list of figures. Each figure has the following properties: - * - status: standard or recent - * - name: figure label - * - value: figure value (number) - * - trand: if defined, has a message and since properties - * - sparkline: if defined, has a list of points - * - date: last update time - * - updated: formatted relative update date. - * - url: URL to the report the figures came from - * - source: short name of the source - * - #more: indicates if there are more figures that can be shown. - * - #dataset: if defined, has a url and title properties - */ - public function getKeyFiguresBuild($iso3, $country) { - return []; - } - - /** - * Get the ReliefWeb key figures for the country. - * - * @param string $iso3 - * ISO3 code of the country for which to retrieve the key figures. - * @param string $country - * Country name. - * - * @return array - * Return an associative array with the key figures for the country - * (empty if none was found). This render array has the following keys: - * - langcode: language iso 2 code - * - country: name of the country the figures are for - * - figures: list of figures. Each figure has the following properties: - * - status: standard or recent - * - name: figure label - * - value: figure value (number) - * - trand: if defined, has a message and since properties - * - sparkline: if defined, has a list of points - * - date: last update time - * - updated: formatted relative update date. - * - url: URL to the report the figures came from - * - source: short name of the source - * - dataset: if defined, has a url and title properties - */ - public function getKeyFigures($iso3, $country) { - return NULL; - } - -} diff --git a/html/modules/custom/reliefweb_key_figures/templates/reliefweb-key-figures.html.twig b/html/modules/custom/reliefweb_key_figures/templates/reliefweb-key-figures.html.twig deleted file mode 100644 index c8619c17a..000000000 --- a/html/modules/custom/reliefweb_key_figures/templates/reliefweb-key-figures.html.twig +++ /dev/null @@ -1,76 +0,0 @@ -{# - -/** - * @file - * Template file for the key figures block. - * - * Available variables; - * - level: heading level (defaults to 2) - * - id: section id (defaults to 'key-figures') - * - title: the title for the section - * - country: name of the country the figures are for - * - figures: list of figures. Each figure has the following properties: - * - status: standard or recent - * - name: figure label - * - value: figure value (number) - * - trand: if defined, has a message and since properties - * - sparkline: if defined, has a list of points - * - date: last update time - * - updated: formatted relative update date. - * - url: URL to the report the figures came from - * - source: short name of the source - * - more: indicates if there are more figures that can be shown. - * - dataset: if defined, has a url and title properties - * - * @todo provide a better alternative to "number_format" that supports - * localization. - * - * @todo use something else than "date" for the formatting to better handle - * localization. - */ - -#} -