├── tobefair_framework ├── py.typed ├── __init__.py ├── core │ ├── __init__.py │ ├── collector │ │ ├── __init__.py │ │ ├── metadata_source_repository.py │ │ └── metadata_collector.py │ ├── evaluator │ │ ├── __init__.py │ │ └── fairness_principle_evaluator.py │ ├── configuration │ │ ├── __init__.py │ │ ├── fairness_configuration_dao.py │ │ └── fairness_configuration_file_dao.py │ └── notification │ │ ├── __init__.py │ │ ├── contexts.py │ │ ├── notifications_middleware.py │ │ └── notification_context.py ├── model │ ├── __init__.py │ ├── composite │ │ ├── __init__.py │ │ ├── composite.py │ │ ├── identifiable_composite.py │ │ └── leaf_result.py │ ├── metadata │ │ ├── __init__.py │ │ ├── metadata_format.py │ │ ├── metadata_record.py │ │ ├── metadata_source.py │ │ ├── metadata_offering_method.py │ │ ├── metadata_keys.py │ │ └── metadata_standard.py │ ├── results │ │ ├── __init__.py │ │ ├── test_execution_status.py │ │ └── test_specific_recommendation.py │ ├── configuration │ │ ├── __init__.py │ │ ├── fair_principle_configuration.py │ │ ├── fair_dimension_configuration.py │ │ └── fairness_metric_configuration.py │ ├── identifier │ │ ├── __init__.py │ │ ├── identifier_url.py │ │ ├── identifier_type.py │ │ ├── id.py │ │ ├── identifier_info.py │ │ ├── fair_dimension_id.py │ │ └── fair_principle_id.py │ ├── alternate_test_behavior.py │ ├── landing_page.py │ ├── fairness_evaluation_request.py │ ├── accept_type.py │ ├── digital_object_info.py │ ├── recommendation.py │ └── fairness_evaluation_maturity.py ├── controller │ ├── __init__.py │ └── configuration_controller.py ├── tool_example │ ├── __init__.py │ ├── metadata_collector_schema_org_json_ld_simple.py │ ├── digital_object_collector_from_file.py │ ├── main_example.py │ └── readme.md ├── framework_constants.py └── module.py ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── question.md │ ├── feature_request.md │ └── bug_report.md ├── SUPPORT.md └── CONTRIBUTING.md ├── tobefair-frontend ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── sort.png │ │ ├── li-icon.png │ │ ├── badge_animado.gif │ │ ├── explore-graph.png │ │ ├── right-arrow.png │ │ └── checkmark--filled.svg │ ├── app │ │ ├── result │ │ │ ├── result.component.css │ │ │ ├── result.component.html │ │ │ ├── result.component.ts │ │ │ └── result.component.spec.ts │ │ ├── details │ │ │ ├── details.component.css │ │ │ ├── details.component.html │ │ │ ├── details.component.ts │ │ │ └── details.component.spec.ts │ │ ├── explorer │ │ │ ├── explorer.component.css │ │ │ ├── explorer.component.html │ │ │ ├── explorer.component.ts │ │ │ └── explorer.component.spec.ts │ │ ├── glossary │ │ │ ├── glossary.component.css │ │ │ ├── glossary.component.html │ │ │ ├── glossary.component.ts │ │ │ └── glossary.component.spec.ts │ │ ├── result-report │ │ │ ├── result-report.component.css │ │ │ ├── result-report.component.html │ │ │ ├── result-report.component.ts │ │ │ └── result-report.component.spec.ts │ │ ├── tool-glossary │ │ │ ├── tool-glossary.component.css │ │ │ ├── tool-glossary.component.html │ │ │ ├── tool-glossary.component.ts │ │ │ └── tool-glossary.component.spec.ts │ │ ├── user-guide │ │ │ ├── user-guide.component.html │ │ │ ├── user-guide.component.css │ │ │ ├── user-guide.component.ts │ │ │ └── user-guide.component.spec.ts │ │ ├── app.component.css │ │ ├── link-button │ │ │ ├── link-button.component.html │ │ │ ├── link-button.component.ts │ │ │ ├── link-button.component.css │ │ │ └── link-button.component.spec.ts │ │ ├── app.config.ts │ │ ├── evaluation.service.spec.ts │ │ ├── home │ │ │ ├── home.component.spec.ts │ │ │ ├── home.component.html │ │ │ ├── home.component.ts │ │ │ └── home.component.css │ │ ├── app.component.ts │ │ ├── app.component.spec.ts │ │ ├── app.component.html │ │ └── app.routes.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.css ├── projects │ └── to-be-fair │ │ ├── src │ │ ├── lib │ │ │ ├── assets │ │ │ │ ├── .gitkeep │ │ │ │ ├── sort.png │ │ │ │ ├── .DS_Store │ │ │ │ ├── li-icon.png │ │ │ │ ├── right-arrow.png │ │ │ │ ├── user-guide │ │ │ │ │ ├── .DS_Store │ │ │ │ │ ├── home │ │ │ │ │ │ ├── URI.png │ │ │ │ │ │ └── home-page.png │ │ │ │ │ ├── details │ │ │ │ │ │ ├── score.png │ │ │ │ │ │ ├── failed.png │ │ │ │ │ │ ├── losses.png │ │ │ │ │ │ ├── metric.png │ │ │ │ │ │ ├── passed.png │ │ │ │ │ │ ├── result.png │ │ │ │ │ │ ├── principle.png │ │ │ │ │ │ ├── test-open.png │ │ │ │ │ │ ├── details-page.png │ │ │ │ │ │ ├── not-executed.png │ │ │ │ │ │ ├── test-closed.png │ │ │ │ │ │ └── recommendation.png │ │ │ │ │ ├── result │ │ │ │ │ │ ├── badge.png │ │ │ │ │ │ ├── button.png │ │ │ │ │ │ └── result-page.png │ │ │ │ │ ├── explorer │ │ │ │ │ │ ├── graph.png │ │ │ │ │ │ ├── header.png │ │ │ │ │ │ ├── legend.png │ │ │ │ │ │ ├── explorer-page.png │ │ │ │ │ │ └── priority-recommendations.png │ │ │ │ │ ├── full-report │ │ │ │ │ │ ├── download-button.png │ │ │ │ │ │ └── full-report-page.png │ │ │ │ │ ├── FAIR-glossary │ │ │ │ │ │ └── FAIR-glossary-page.png │ │ │ │ │ └── tool-glossary │ │ │ │ │ │ └── tool-glossary-page.png │ │ │ │ └── checkmark--filled.svg │ │ │ ├── to-be-fair.model.ts │ │ │ ├── legend │ │ │ │ ├── legend.component.css │ │ │ │ ├── legend.component.html │ │ │ │ └── legend.component.spec.ts │ │ │ ├── badge │ │ │ │ ├── badge.component.html │ │ │ │ ├── badge.component.css │ │ │ │ └── badge.component.spec.ts │ │ │ ├── functions │ │ │ │ └── functions.ts │ │ │ ├── to-be-fair.service.ts │ │ │ ├── error │ │ │ │ ├── error.component.css │ │ │ │ ├── error.component.html │ │ │ │ ├── error.component.ts │ │ │ │ └── error.component.spec.ts │ │ │ ├── recommendation-list │ │ │ │ ├── recommendation-list.component.css │ │ │ │ ├── recommendation-list.component.html │ │ │ │ └── recommendation-list.component.ts │ │ │ ├── constants │ │ │ │ └── constants.ts │ │ │ ├── to-be-fair.module.ts │ │ │ ├── user-guide │ │ │ │ ├── user-guide.component.ts │ │ │ │ ├── user-guide.component.spec.ts │ │ │ │ └── user-guide.component.css │ │ │ ├── to-be-fair.component.ts │ │ │ ├── result-report │ │ │ │ ├── result-report.component.css │ │ │ │ ├── result-report.component.spec.ts │ │ │ │ └── result-report.component.html │ │ │ ├── to-be-fair.config.ts │ │ │ ├── to-be-fair.service.spec.ts │ │ │ ├── header │ │ │ │ ├── header.component.spec.ts │ │ │ │ ├── header.component.css │ │ │ │ └── header.component.html │ │ │ ├── explorer │ │ │ │ ├── explorer.component.html │ │ │ │ ├── explorer.component.spec.ts │ │ │ │ └── explorer.component.css │ │ │ ├── result │ │ │ │ ├── result.component.spec.ts │ │ │ │ └── result.component.css │ │ │ ├── details │ │ │ │ └── details.component.spec.ts │ │ │ ├── to-be-fair.component.spec.ts │ │ │ ├── evaluate │ │ │ │ ├── evaluate.component.spec.ts │ │ │ │ ├── evaluate.component.css │ │ │ │ ├── evaluate.component.html │ │ │ │ └── evaluate.component.ts │ │ │ ├── glossary │ │ │ │ ├── glossary.component.spec.ts │ │ │ │ └── glossary.component.ts │ │ │ ├── tool-glossary │ │ │ │ ├── tool-glossary.component.spec.ts │ │ │ │ └── tool-glossary.component.ts │ │ │ ├── carbon │ │ │ │ └── carbon.module.ts │ │ │ ├── env-var.guard.ts │ │ │ ├── to-be-fair.routes.ts │ │ │ └── notification.service.ts │ │ ├── models │ │ │ ├── FAIRnotification.ts │ │ │ ├── fairness-evaluation.ts │ │ │ └── fairness-evaluation-api.ts │ │ └── public-api.ts │ │ ├── ng-package.json │ │ ├── tsconfig.lib.prod.json │ │ ├── tsconfig.spec.json │ │ ├── tsconfig.lib.json │ │ └── README.md ├── .whitesource ├── server │ ├── package.json │ └── server.js ├── tsconfig.app.json ├── tsconfig.spec.json ├── .editorconfig ├── Dockerfile ├── eslint.config.mjs ├── scripts │ └── build.sh ├── .gitignore ├── tsconfig.json └── README.md ├── .flake8rc ├── .dockerignore ├── MAINTAINERS.md ├── pytest.ini ├── tests ├── __init__.py ├── utils │ ├── test_dict_utils.py │ └── manage_fairness_response.py ├── service │ ├── test_configuration_endpoint.py │ └── test_result_order.py ├── framework │ └── test_configuration_file_dao.py ├── evaluators │ ├── reusability │ │ └── test_R1_1_evaluator.py │ └── findability │ │ └── test_F3_02M_1.py └── data_for_testing │ └── mock_community_metadata_standards.json ├── tobefair_backend ├── __init__.py ├── model │ ├── __init__.py │ ├── resources │ │ ├── __init__.py │ │ ├── license_information.py │ │ ├── typed_link.py │ │ ├── data_record.py │ │ └── data_size.py │ ├── uri_protocol.py │ ├── file_format.py │ ├── response_wrapper.py │ └── response_header_wrapper.py ├── service │ ├── __init__.py │ ├── routes │ │ ├── __init__.py │ │ ├── check_app_routes.py │ │ ├── configuration_routes.py │ │ └── evaluation_routes.py │ └── main.py ├── utils │ ├── __init__.py │ ├── list_utils.py │ └── dict_utils.py ├── collector │ ├── __init__.py │ └── digital_object_collector_from_url.py ├── repository │ ├── __init__.py │ ├── uri_protocol_repository.py │ ├── json_dictionary_repository.py │ ├── metadata_offering_method_repository.py │ └── file_format_repository.py ├── database │ ├── metadata_offering_methods.json │ ├── metadata_formats.json │ └── standard_uri_protocols.json ├── constants.py └── principle_evaluators │ └── fairness_test.py ├── tobefair_backend_dev_requirements.tx ├── requirements.txt ├── CHANGELOG.md ├── tobefair_backend_requirements.txt ├── bin ├── a_shell_script └── brief_salutation ├── .pre-commit-config.yaml ├── mypy.ini ├── docs ├── index.md ├── Makefile ├── make.bat └── _templates │ └── module.rst ├── .travis └── deploy.sh ├── bench └── README.md ├── Makefile.conf ├── Dockerfile ├── setup.py ├── dev_requirements.txt ├── setup.cfg └── .gitignore /tobefair_framework/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @lga 2 | -------------------------------------------------------------------------------- /tobefair-frontend/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result/result.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/details/details.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/explorer/explorer.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/glossary/glossary.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.model.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result-report/result-report.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/tool-glossary/tool-glossary.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.flake8rc: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E741,F403,F405,W503 3 | max-line-length = 88 -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/legend/legend.component.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | bench/ 2 | docs/ 3 | data/ 4 | models/ 5 | notebooks/ 6 | venv/ 7 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # MAINTAINERS 2 | 3 | Leonardo Guerreiro Azevedo - lga@br.ibm.com -------------------------------------------------------------------------------- /tobefair-frontend/src/app/details/details.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result/result.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/explorer/explorer.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/glossary/glossary.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = tests 3 | addopts = --cov=tobefair_framework --cov-report=html -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/user-guide/user-guide.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tobefair_backend/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result-report/result-report.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/tool-glossary/tool-glossary.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tobefair_backend/model/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_backend/service/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_backend/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/core/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/model/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair-frontend/.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "settingsInheritedFrom": "whitesource-config/whitesource-config@master" 3 | } -------------------------------------------------------------------------------- /tobefair_backend/collector/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_backend/repository/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_backend_dev_requirements.tx: -------------------------------------------------------------------------------- 1 | httpx==0.27.0 2 | jsondiff==2.2.1 3 | mock==5.1.0 4 | types-mock==5.1.0.20240425 -------------------------------------------------------------------------------- /tobefair_framework/controller/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair-frontend/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/src/favicon.ico -------------------------------------------------------------------------------- /tobefair_backend/model/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_backend/service/routes/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/core/collector/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/core/evaluator/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/model/composite/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/model/metadata/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/model/results/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/tool_example/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/core/configuration/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/core/notification/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/model/configuration/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /tobefair_framework/model/identifier/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true # set to false if you want to enforce issues via templates only 2 | -------------------------------------------------------------------------------- /tobefair-frontend/src/assets/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/src/assets/sort.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/legend/legend.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /tobefair-frontend/src/assets/li-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/src/assets/li-icon.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/badge/badge.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | :host div.navbar { 2 | padding: 0 1em; 3 | } 4 | 5 | .navbar { 6 | margin-bottom: 50px; 7 | } 8 | -------------------------------------------------------------------------------- /tobefair-frontend/src/assets/badge_animado.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/src/assets/badge_animado.gif -------------------------------------------------------------------------------- /tobefair-frontend/src/assets/explore-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/src/assets/explore-graph.png -------------------------------------------------------------------------------- /tobefair-frontend/src/assets/right-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/src/assets/right-arrow.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/functions/functions.ts: -------------------------------------------------------------------------------- 1 | export function getArrayFromDict(results: any): any[] { 2 | return Object.values(results); 3 | } 4 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/sort.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/.DS_Store -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/li-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/li-icon.png -------------------------------------------------------------------------------- /tobefair_backend/utils/list_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | 5 | def remove_duplicates(l: list): 6 | return list(set(l)) 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | #pip package names required by the package, and exact versions you know to work 2 | click==8.1.7 3 | hashID==3.1.4 4 | idutils==1.2.1 5 | pydantic==2.12.3 6 | fastapi==0.116.1 -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/right-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/right-arrow.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [0.0.1] - 2025-12-03 6 | 7 | - Release of the first version of 2BFAIR-framework. 8 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/.DS_Store -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/home/URI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/home/URI.png -------------------------------------------------------------------------------- /tobefair-frontend/src/app/user-guide/user-guide.component.css: -------------------------------------------------------------------------------- 1 | :host div.outer { 2 | padding: 1em; 3 | } 4 | /* Heading styles */ 5 | h2 { 6 | font-weight: normal; 7 | margin-block-start: 0; 8 | } 9 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/score.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/score.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/result/badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/result/badge.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/result/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/result/button.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/failed.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/losses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/losses.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/metric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/metric.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/passed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/passed.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/result.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/graph.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/header.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/legend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/legend.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/home/home-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/home/home-page.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/principle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/principle.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/test-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/test-open.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/result/result-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/result/result-page.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/details-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/details-page.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/not-executed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/not-executed.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/test-closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/test-closed.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/recommendation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/details/recommendation.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/explorer-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/explorer-page.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/full-report/download-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/full-report/download-button.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/full-report/full-report-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/full-report/full-report-page.png -------------------------------------------------------------------------------- /tobefair_backend/model/resources/license_information.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class LicenseInformation(BaseModel): 8 | raw_value: str 9 | -------------------------------------------------------------------------------- /tobefair_framework/core/collector/metadata_source_repository.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from abc import ABC 5 | 6 | 7 | class MetadataSourceRepository(ABC): 8 | 9 | pass 10 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class ToBeFairService { 7 | 8 | constructor() { } 9 | } 10 | -------------------------------------------------------------------------------- /tobefair_framework/core/notification/contexts.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from contextvars import ContextVar 5 | 6 | request_id_var: ContextVar[str] = ContextVar("request_id", default="") 7 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/FAIR-glossary/FAIR-glossary-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/FAIR-glossary/FAIR-glossary-page.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/priority-recommendations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/explorer/priority-recommendations.png -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/tool-glossary/tool-glossary-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IBM/2BFAIR-framework/main/tobefair-frontend/projects/to-be-fair/src/lib/assets/user-guide/tool-glossary/tool-glossary-page.png -------------------------------------------------------------------------------- /tobefair_backend_requirements.txt: -------------------------------------------------------------------------------- 1 | bs4==0.0.2 2 | extruct==0.16.0 3 | fastapi==0.121.0 4 | jmespath==1.0.1 5 | lxml==5.1.0 6 | lxml_html_clean==0.4.0 7 | python-mimeparse==1.6.0 8 | tika==2.6.0 9 | types-jmespath==1.0.2.20240106 10 | uvicorn==0.29.0 -------------------------------------------------------------------------------- /tobefair_framework/model/alternate_test_behavior.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | 6 | 7 | class AlternateTestBehavior(Enum): 8 | skip = "skip" 9 | fail = "fail" 10 | -------------------------------------------------------------------------------- /tobefair_framework/model/metadata/metadata_format.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class MetadataFormat(BaseModel): 8 | label: str 9 | acronym: str 10 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/to-be-fair", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | }, 7 | "assets": ["src/lib/assets"] 8 | } 9 | -------------------------------------------------------------------------------- /tobefair_framework/model/identifier/identifier_url.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class IdentifierURL(BaseModel): 8 | url: str 9 | is_web_accessible: bool 10 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/error/error.component.css: -------------------------------------------------------------------------------- 1 | * { 2 | text-align: center; 3 | } 4 | .error-container { 5 | margin: 50px auto; 6 | padding: 20px; 7 | border-radius: 5px; 8 | } 9 | h1 { 10 | font-size: 32px; 11 | margin-bottom: 20px; 12 | } 13 | -------------------------------------------------------------------------------- /tobefair_framework/framework_constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | ALLOW_DUPLICATE_TESTS = False 5 | FAIRNESS_CONFIGURATION_FILE_PATH_FOR_THE_FRAMEWORK = ( 6 | "./tobefair_framework/tool_example/fairness_configuration.json" 7 | ) 8 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/error/error.component.html: -------------------------------------------------------------------------------- 1 |
2 | 8 |

Error

9 |

{{ error }}

10 |
11 | -------------------------------------------------------------------------------- /tobefair_framework/model/landing_page.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class LandingPage(BaseModel): 8 | encoded_hmtl_body: bytes | None = None 9 | decoded_html_body: str 10 | url: str 11 | -------------------------------------------------------------------------------- /tobefair_framework/model/results/test_execution_status.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | 6 | 7 | class TestExecutionStatus(str, Enum): 8 | passed = "passed" 9 | failed = "failed" 10 | not_executed = "not executed" 11 | -------------------------------------------------------------------------------- /bin/a_shell_script: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # LICENSED INTERNAL CODE. PROPERTY OF IBM. 4 | # IBM Research Licensed Internal Code 5 | # (C) Copyright IBM Corp. 2025 6 | # ALL RIGHTS RESERVED 7 | 8 | echo "We can also ship bash scripts with the python package if we have to." 9 | echo "What matters is the shebang." 10 | -------------------------------------------------------------------------------- /tobefair_framework/model/identifier/identifier_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | 6 | 7 | class IdentifierType(str, Enum): 8 | UUID = "uuid" 9 | HASH = "hash" 10 | GUID = "guid" 11 | NOT_IDENTIFIED = "not identified" 12 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/recommendation-list/recommendation-list.component.css: -------------------------------------------------------------------------------- 1 | 2 | a { 3 | text-decoration: none; 4 | color: #0f62fe; 5 | font-size: 15px; 6 | padding-top: 5px; 7 | display: block; 8 | font-weight: normal; 9 | } 10 | 11 | a:hover { 12 | color: #8a3ffc 13 | } -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.2.0 4 | hooks: 5 | - id: check-yaml 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/psf/black 9 | rev: 22.3.0 10 | hooks: 11 | - id: black 12 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | [mypy-extruct.*] 3 | ignore_missing_imports=True 4 | [mypy-hashid.*] 5 | ignore_missing_imports=True 6 | [mypy-idutils.*] 7 | ignore_missing_imports=True 8 | [mypy-lxml.*] 9 | ignore_missing_imports=True 10 | [mypy-mimeparse.*] 11 | ignore_missing_imports=True 12 | [mypy-tika.*] 13 | ignore_missing_imports=True -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.lib.json", 4 | "compilerOptions": { 5 | "declarationMap": false 6 | }, 7 | "angularCompilerOptions": { 8 | "compilationMode": "partial" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tobefair-frontend/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "to-be-fair-standalone", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "start": "node server" 6 | }, 7 | "private": true, 8 | "engines": { 9 | "node": "10.x" 10 | }, 11 | "dependencies": { 12 | "cors": "^2.8.5", 13 | "express": "4.21.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/constants/constants.ts: -------------------------------------------------------------------------------- 1 | export const ESSENTIAL = 'Essential'; 2 | export const IMPORTANT = 'Important'; 3 | export const USEFUL = 'Useful'; 4 | export const FINDABILITY_CODE = 'F'; 5 | export const ACCESSIBILITY_CODE = 'A'; 6 | export const INTEROPERABILITY_CODE = 'I'; 7 | export const REUSABILITY_CODE = 'R'; 8 | -------------------------------------------------------------------------------- /tobefair-frontend/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": ["./types/carbon-icons.d.ts"] 7 | }, 8 | "files": ["src/main.ts"], 9 | "include": ["src/**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # 2BFAIR Framework 2 | 3 | ## API 4 | 5 | ```{toctree} 6 | --- 7 | maxdepth: 1 8 | --- 9 | tobefair_framework API 10 | ``` 11 | 12 | 13 | ## Documentation examples 14 | 15 | ```{toctree} 16 | --- 17 | maxdepth: 2 18 | --- 19 | Example page with markdown source 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { CarbonModule } from './carbon/carbon.module'; 4 | 5 | @NgModule({ 6 | declarations: [], 7 | imports: [CommonModule, CarbonModule], 8 | }) 9 | export class ToBeFairModule {} 10 | -------------------------------------------------------------------------------- /tobefair_backend/service/routes/check_app_routes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from fastapi import APIRouter 5 | 6 | check_app_router = APIRouter() 7 | 8 | TAG_FAIRNESS_EVALUATION = "Check app" 9 | 10 | 11 | @check_app_router.get("/health") 12 | async def check_app_health(): 13 | return True 14 | -------------------------------------------------------------------------------- /tobefair_framework/model/fairness_evaluation_request.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class FAIRnessEvaluationRequest(BaseModel): 8 | resource_id: str = "https://doi.org/10.1594/PANGAEA.893286" 9 | community: str | None = None 10 | task: str | None = None 11 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/user-guide/user-guide.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'lib-user-guide', 5 | standalone: true, 6 | imports: [], 7 | templateUrl: './user-guide.component.html', 8 | styleUrl: './user-guide.component.css', 9 | }) 10 | export class UserGuideComponent {} 11 | -------------------------------------------------------------------------------- /tobefair-frontend/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'lib-to-be-fair', 5 | standalone: true, 6 | imports: [], 7 | template: ` 8 |

9 | to-be-fair works! 10 |

11 | `, 12 | styles: `` 13 | }) 14 | export class ToBeFairComponent { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/models/FAIRnotification.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | export interface FAIRNotification { 5 | id: number; 6 | type: "error" | "info" | "info-square" | "warning" | "warning-alt" | "success"; 7 | title: string; 8 | description: string; 9 | isOpen: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /tobefair-frontend/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2BFAIR 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tobefair-frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { bootstrapApplication } from '@angular/platform-browser'; 5 | import { appConfig } from './app/app.config'; 6 | import { AppComponent } from './app/app.component'; 7 | 8 | bootstrapApplication(AppComponent, appConfig) 9 | .catch((err) => console.error(err)); 10 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../../out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "**/*.spec.ts", 12 | "**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tobefair-frontend/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;700&display=swap"); 4 | /*@import "carbon-components/scss/globals/scss/styles"; 5 | 6 | @import "../../styles/dist/carbon-aux.css";*/ 7 | 8 | * { 9 | font-family: "IBM Plex Sans", sans-serif; 10 | } 11 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/result-report/result-report.component.css: -------------------------------------------------------------------------------- 1 | .outer { 2 | padding: 1em; 3 | } 4 | 5 | h4 { 6 | color: #6f6f6f; 7 | } 8 | 9 | p { 10 | margin-top: 10px; 11 | margin-left: 25px; 12 | } 13 | 14 | h2 { 15 | margin-top: 20px; 16 | } 17 | 18 | button { 19 | float: right; 20 | margin-top: 10px; 21 | margin-right: 10px; 22 | display: inline-block; 23 | } 24 | -------------------------------------------------------------------------------- /tobefair_framework/model/composite/composite.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from abc import ABC, abstractmethod 5 | from typing import Generic, List, TypeVar 6 | 7 | Child = TypeVar("Child", bound="Composite") 8 | 9 | 10 | class Composite(Generic[Child], ABC): 11 | @abstractmethod 12 | def get_children(self) -> List[Child] | None: 13 | pass 14 | -------------------------------------------------------------------------------- /.travis/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # some steps to (build and) upload your built artifacts from travis. 4 | # this might include steps to 5 | # - install cli tools to interact with services (e.g. ibmcloud, openshift, ...) 6 | # - log in to the registy 7 | # - tag image/images accordingly for pushing them 8 | # - actually pushing/uploading the images 9 | # - trigger other events now that these images are available 10 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../../out-tsc/lib", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": ["../../types/carbon-icons.d.ts"] 10 | }, 11 | "exclude": ["**/*.spec.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Getting support 2 | 3 | ## How do I get help? 4 | - As a first step, please search in the [existing issues](https://github.ibm.com/brl-kbe/2BFAIR-framework/issues?q=is%3Aissue) 5 | to check if your point has already been addressed. 6 | - If that is not the case, go ahead and [create an issue](https://github.ibm.com/brl-kbe/2BFAIR-framework/issues/new/choose) 7 | of the respective type, providing the details as instructed in the template. 8 | -------------------------------------------------------------------------------- /tobefair_framework/model/accept_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import List 5 | 6 | from pydantic import BaseModel 7 | 8 | 9 | class AcceptType(BaseModel): 10 | def make_accept_header(self): 11 | header = "" 12 | for mime_type in self.mime_types: 13 | header += mime_type + ", " 14 | return header[:-2] 15 | 16 | mime_types: List[str] 17 | -------------------------------------------------------------------------------- /tobefair-frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Editor configuration, see https://editorconfig.org 5 | root = true 6 | 7 | [*] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.ts] 15 | quote_type = single 16 | 17 | [*.md] 18 | max_line_length = off 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What do you need help with? Please describe what you would like to do.** 11 | A clear and concise description of what you want to do and what you need help with. 12 | E.g. How do I configure [...] in order to achieve [...] 13 | 14 | **Additional context** 15 | Add any further related context here. 16 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.config.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationConfig } from '@angular/core'; 2 | import { provideRouter } from '@angular/router'; 3 | import { routes } from './to-be-fair.routes'; 4 | 5 | import { HttpClientModule } from '@angular/common/http'; 6 | import { importProvidersFrom } from '@angular/core'; 7 | 8 | export const appConfig: ApplicationConfig = { 9 | providers: [provideRouter(routes), importProvidersFrom(HttpClientModule)], 10 | }; 11 | -------------------------------------------------------------------------------- /bench/README.md: -------------------------------------------------------------------------------- 1 | # The workbench close to the library 2 | 3 | This is just an example folder to tell you that not all your code needs to be part of the package. 4 | 5 | For example there could be `experiments/` with training scripts or `notebooks/` with jupyter notebooks where you try stuff. 6 | 7 | This stuff will still be under version control and can conveniently import from the package. 8 | 9 | Files here will not be installed, but could be configured to be via `package_data` in `setup.py`. 10 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ToBeFairService } from './to-be-fair.service'; 4 | 5 | describe('ToBeFairService', () => { 6 | let service: ToBeFairService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(ToBeFairService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result/result.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component } from '@angular/core'; 5 | import { ResultComponent as LibResultComponent } from '@dwb/to-be-fair'; 6 | 7 | @Component({ 8 | selector: 'app-result', 9 | standalone: true, 10 | imports: [LibResultComponent], 11 | templateUrl: './result.component.html', 12 | styleUrl: './result.component.css', 13 | }) 14 | export class ResultComponent {} 15 | -------------------------------------------------------------------------------- /tobefair_framework/core/collector/metadata_collector.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from abc import ABC 5 | 6 | from pydantic import BaseModel 7 | 8 | from tobefair_framework.model.metadata.metadata_record import MetadataRecord 9 | 10 | 11 | class MetadataCollector(ABC, BaseModel): 12 | 13 | @classmethod 14 | def get_metadata_record( 15 | cls, raw_digital_object: str | dict 16 | ) -> MetadataRecord | None: 17 | return None 18 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/link-button/link-button.component.html: -------------------------------------------------------------------------------- 1 | 10 |
-------------------------------------------------------------------------------- /tobefair-frontend/src/app/details/details.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component } from '@angular/core'; 5 | 6 | import { DetailsComponent as LibDetailsComponent } from '@dwb/to-be-fair'; 7 | 8 | @Component({ 9 | selector: 'app-details', 10 | standalone: true, 11 | imports: [LibDetailsComponent], 12 | templateUrl: './details.component.html', 13 | styleUrl: './details.component.css', 14 | }) 15 | export class DetailsComponent {} 16 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/glossary/glossary.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component } from '@angular/core'; 5 | import { GlossaryComponent as LibGlossaryComponent } from '@dwb/to-be-fair'; 6 | 7 | @Component({ 8 | selector: 'app-glossary', 9 | standalone: true, 10 | imports: [LibGlossaryComponent], 11 | templateUrl: './glossary.component.html', 12 | styleUrl: './glossary.component.css', 13 | }) 14 | export class GlossaryComponent {} 15 | -------------------------------------------------------------------------------- /Makefile.conf: -------------------------------------------------------------------------------- 1 | # -*- mode: makefile -*- 2 | 3 | NAME= 2BFAIR-framework 4 | PACKAGE=tobefair_backend 5 | TEST_FOLDER=tests 6 | DESCRIPTION= 7 | AUTHOR= IBM 8 | EMAIL= lga@br.ibm.com 9 | URL= https://github.ibm.com/brl-kbe/2BFAIR-framework.git 10 | URL_SSH= git@github.ibm.com:brl-kbe/2BFAIR-framework.git 11 | 12 | COPYRIGHT= IBM Corp. 13 | COPYRIGHT_START_YEAR= 2025 14 | LICENSE= Apache-2.0 15 | 16 | COVERAGERC_EXCLUDE_LINES+= MustBeImplementedInSubclass 17 | COVERAGERC_OMIT= 18 | MYPY_OPTIONS= 19 | TOX_SETENV= 20 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/explorer/explorer.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component, inject } from '@angular/core'; 5 | 6 | import { ExplorerComponent as LibExplorerComponent } from '@dwb/to-be-fair'; 7 | 8 | @Component({ 9 | selector: 'app-explorer', 10 | standalone: true, 11 | imports: [LibExplorerComponent], 12 | templateUrl: './explorer.component.html', 13 | styleUrl: './explorer.component.css', 14 | }) 15 | export class ExplorerComponent {} 16 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/user-guide/user-guide.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component } from '@angular/core'; 5 | import { UserGuideComponent as LibUserGuideComponent } from '@dwb/to-be-fair'; 6 | 7 | @Component({ 8 | selector: 'app-user-guide', 9 | standalone: true, 10 | imports: [LibUserGuideComponent], 11 | templateUrl: './user-guide.component.html', 12 | styleUrl: './user-guide.component.css', 13 | }) 14 | export class UserGuideComponent {} 15 | -------------------------------------------------------------------------------- /tobefair_backend/model/uri_protocol.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class URIProtocol(BaseModel): 8 | name: str 9 | id: str 10 | 11 | def __eq__(self, value: object) -> bool: 12 | if isinstance(value, URIProtocol): 13 | return value.id == self.id and value.name == self.name 14 | elif isinstance(value, str): 15 | return value == self.id or value == self.name 16 | return False 17 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ApplicationConfig } from '@angular/core'; 5 | import { provideRouter } from '@angular/router'; 6 | import { routes } from './app.routes'; 7 | 8 | import { HttpClientModule } from '@angular/common/http'; 9 | import { importProvidersFrom } from '@angular/core'; 10 | 11 | export const appConfig: ApplicationConfig = { 12 | providers: [provideRouter(routes), importProvidersFrom(HttpClientModule)], 13 | }; 14 | -------------------------------------------------------------------------------- /tobefair_framework/model/metadata/metadata_record.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | from tobefair_framework.model.metadata.metadata_keys import ( 7 | MetadataSourceKeys, 8 | MetadataStandardName, 9 | ) 10 | 11 | 12 | class MetadataRecord(BaseModel): 13 | 14 | is_machine_retrieved: bool 15 | raw_value: dict 16 | metadata_source_key: MetadataSourceKeys | None = None 17 | metadata_standard_name: MetadataStandardName | None = None 18 | -------------------------------------------------------------------------------- /tobefair_framework/core/configuration/fairness_configuration_dao.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from abc import ABC, abstractmethod 5 | 6 | from pydantic import BaseModel 7 | 8 | from tobefair_framework.model.configuration.fairness_configuration import ( 9 | FAIRnessConfiguration, 10 | ) 11 | 12 | 13 | class FAIRnessConfigurationDAO(ABC, BaseModel): 14 | 15 | @abstractmethod 16 | def read_configuration(self) -> FAIRnessConfiguration: 17 | return FAIRnessConfiguration() 18 | -------------------------------------------------------------------------------- /tobefair_framework/model/metadata/metadata_source.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | from tobefair_framework.model.metadata.metadata_format import MetadataFormat 7 | from tobefair_framework.model.metadata.metadata_offering_method import ( 8 | MetadataOfferingMethod, 9 | ) 10 | 11 | 12 | class MetadataSource(BaseModel): 13 | label: str 14 | acronym: str 15 | method: MetadataOfferingMethod | None = None 16 | format: MetadataFormat | None = None 17 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result-report/result-report.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component } from '@angular/core'; 5 | import { ResultReportComponent as LibResultReportComponent } from '@dwb/to-be-fair'; 6 | 7 | @Component({ 8 | selector: 'app-result-report', 9 | standalone: true, 10 | imports: [LibResultReportComponent], 11 | templateUrl: './result-report.component.html', 12 | styleUrl: './result-report.component.css', 13 | }) 14 | export class ResultReportComponent {} 15 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/tool-glossary/tool-glossary.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component } from '@angular/core'; 5 | import { ToolGlossaryComponent as LibToolGlossaryComponent } from '@dwb/to-be-fair'; 6 | 7 | @Component({ 8 | selector: 'aap-tool-glossary', 9 | standalone: true, 10 | imports: [LibToolGlossaryComponent], 11 | templateUrl: './tool-glossary.component.html', 12 | styleUrl: './tool-glossary.component.css', 13 | }) 14 | export class ToolGlossaryComponent {} 15 | -------------------------------------------------------------------------------- /tobefair-frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.access.redhat.com/ubi8/nodejs-20-minimal 2 | 3 | # Create app directory 4 | WORKDIR /usr/src/app 5 | 6 | # Copy server files 7 | COPY server/package.json . 8 | COPY server/server.js . 9 | COPY dist/frontend/browser ../dist/frontend/browser 10 | 11 | USER root 12 | 13 | # If you are building your code for production 14 | RUN npm install --only=production 15 | 16 | EXPOSE 42000 17 | 18 | RUN curl -sf https://gobinaries.com/tj/node-prune | sh 19 | RUN node-prune 20 | 21 | USER 1001 22 | 23 | CMD [ "node", "server.js" ] 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 2 | # setup 3 | RUN mkdir /app && mkdir /data 4 | WORKDIR /app 5 | # install requirements 6 | COPY requirements.txt . 7 | RUN pip install --no-cache-dir -r requirements.txt 8 | # install app 9 | COPY . . 10 | RUN pip install --no-cache-dir -e ".[test]" 11 | # setup dedicated user 12 | RUN adduser --disabled-password --gecos '' app-user 13 | RUN chown -R app-user:app-user /app /data 14 | USER app-user 15 | # setup UTF-8 locale 16 | ENV LC_ALL=C.UTF-8 17 | ENV LANG=C.UTF-8 18 | ENV LC_CTYPE=C.UTF-8 19 | # image default command 20 | CMD ["/bin/bash"] 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # configuration approach followed: 5 | # - whenever possible, prefer pyproject.toml 6 | # - for configurations insufficiently supported by pyproject.toml, use setup.cfg instead 7 | # - setup.py discouraged; minimal stub included only for compatibility with legacy tools 8 | 9 | # Minimal stub for backwards compatibility, e.g. for legacy tools without PEP 660 support. 10 | # See https://setuptools.pypa.io/en/latest/userguide/quickstart.html 11 | from setuptools import setup 12 | 13 | setup() 14 | -------------------------------------------------------------------------------- /tobefair_framework/model/metadata/metadata_offering_method.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel 5 | 6 | # Metadata offering methods corresponds to how the metadata is provided, e.g., 7 | # embedded JSON-LD in HTML (json_in_html), Microdata (microdata), 8 | # HTML meta tags (meta_tags), RDFa (rdfa), typed links (typed_links), 9 | # signposting links (signposting), and Content Negotiation (content_negotiation). 10 | 11 | 12 | class MetadataOfferingMethod(BaseModel): 13 | label: str 14 | acronym: str 15 | -------------------------------------------------------------------------------- /dev_requirements.txt: -------------------------------------------------------------------------------- 1 | # tests 2 | pytest==7.1.2 3 | pytest-cov==3.0.0 4 | # checks 5 | black>=24.3.0 6 | flake8==7.0.0 7 | pep8-naming==0.13.0 8 | mypy==1.10.0 9 | pre-commit==2.18.1 10 | isort==7.0.0 11 | # docs 12 | # pinning sphinx to older version to resolve flake8 conflict under python3.7: flake8 4.0.1 depends on importlib-metadata<4.3; python_version < "3.8" and sphinx 4.4.0 depends on importlib-metadata>=4.4; python_version < "3.10" 13 | sphinx==4.3.2 14 | sphinx-autodoc-typehints==1.17.1 15 | better-apidoc==0.3.2 16 | six==1.16.0 17 | sphinx-rtd-theme==1.0.0 18 | myst-parser==0.17.2 19 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/recommendation-list/recommendation-list.component.html: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/link-button/link-button.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component, Input, input } from '@angular/core'; 5 | 6 | @Component({ 7 | selector: 'app-link-button', 8 | standalone: true, 9 | imports: [], 10 | templateUrl: './link-button.component.html', 11 | styleUrl: './link-button.component.css' 12 | }) 13 | export class LinkButtonComponent { 14 | @Input() label = "Button Label"; 15 | @Input() url = ""; 16 | 17 | redirect() { 18 | window.location.href = this.url; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/evaluation.service.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { TestBed } from '@angular/core/testing'; 5 | 6 | import { EvaluationService } from '../../projects/to-be-fair/src/lib/evaluation.service'; 7 | 8 | describe('EvaluationService', () => { 9 | let service: EvaluationService; 10 | 11 | beforeEach(() => { 12 | TestBed.configureTestingModule({}); 13 | service = TestBed.inject(EvaluationService); 14 | }); 15 | 16 | it('should be created', () => { 17 | expect(service).toBeTruthy(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /tests/utils/test_dict_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import unittest 5 | 6 | from tobefair_backend.utils.dict_utils import remove_empty_fields 7 | 8 | 9 | class TestDictUtils(unittest.TestCase): 10 | def test_remove_empty_fields(self): 11 | d1: dict = {1: "", 2: None, 3: []} 12 | self.assertEqual(remove_empty_fields(d1), {}) 13 | 14 | d2: dict = {4: "foo", 5: 2, 6: [1, 2]} 15 | self.assertEqual(remove_empty_fields(d2), d2) 16 | 17 | d3 = d1.copy() 18 | d3.update(d2) 19 | self.assertEqual(remove_empty_fields(d3), d2) 20 | -------------------------------------------------------------------------------- /tobefair-frontend/src/assets/checkmark--filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tobefair_framework/model/metadata/metadata_keys.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | 6 | 7 | class MetadataStandardName(Enum): 8 | SCHEMA_ORG = "Schema.org" 9 | PROV = "prov" 10 | 11 | 12 | def get_metadata_standard_name_from_str(name: str) -> MetadataStandardName | None: 13 | for member in MetadataStandardName: 14 | if MetadataStandardName(name) == member: 15 | return member 16 | return None 17 | 18 | 19 | class MetadataSourceKeys(Enum): 20 | SCHEMA_ORG_EMBEDDED = "SCHEMAORG_EMBEDDED" 21 | RDFA_EMBEDDED = "RDFA_EMBEDDED" 22 | -------------------------------------------------------------------------------- /tobefair_framework/model/composite/identifiable_composite.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from abc import ABC, abstractmethod 5 | from typing import Generic, TypeVar 6 | 7 | from tobefair_framework.model.composite.composite import Composite 8 | from tobefair_framework.model.identifier.id import ID 9 | 10 | IdentifiableChild = TypeVar("IdentifiableChild", bound="IdentifiableComposite") 11 | 12 | 13 | class IdentifiableComposite( 14 | Generic[IdentifiableChild], Composite[IdentifiableChild], ABC 15 | ): 16 | @property 17 | @abstractmethod 18 | def get_id(self) -> ID: 19 | pass 20 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/assets/checkmark--filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/error/error.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { CarbonModule } from '../carbon/carbon.module'; 3 | import { DataError32 } from '@carbon/icons'; 4 | import { IconService } from 'carbon-components-angular'; 5 | 6 | @Component({ 7 | selector: 'lib-error', 8 | standalone: true, 9 | imports: [CarbonModule], 10 | templateUrl: './error.component.html', 11 | styleUrl: './error.component.css', 12 | }) 13 | export class ErrorComponent { 14 | @Input() error: string | undefined; 15 | 16 | constructor(iconService: IconService) { 17 | iconService.registerAll([DataError32]); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/service/test_configuration_endpoint.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import unittest 5 | 6 | from fastapi.testclient import TestClient 7 | 8 | from tobefair_backend.service.main import app 9 | 10 | 11 | class TestConfigurationEndpoint(unittest.TestCase): 12 | 13 | def setUp(self): 14 | self.client = TestClient(app=app) 15 | self.route = "/configuration" 16 | 17 | @unittest.skip("This needs refactoring in the use of ConfigurationController.") 18 | def test_configuration_route(self): 19 | response = self.client.get(self.route) 20 | assert response.status_code == 200, "Error on requesting configuration." 21 | -------------------------------------------------------------------------------- /tobefair_backend/service/routes/configuration_routes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from fastapi import APIRouter 5 | 6 | from tobefair_framework.controller.configuration_controller import ( 7 | ConfigurationController, 8 | ) 9 | from tobefair_framework.model.configuration.fairness_configuration import ( 10 | FAIRnessConfiguration, 11 | ) 12 | 13 | configuration_router = APIRouter() 14 | 15 | TAG_FAIRNESS_CONFIGURATION = "Configuration" 16 | 17 | 18 | @configuration_router.get("/configuration", tags=[TAG_FAIRNESS_CONFIGURATION]) 19 | async def configuration() -> FAIRnessConfiguration: 20 | return ConfigurationController.get_configuration() 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. E.g. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/link-button/link-button.component.css: -------------------------------------------------------------------------------- 1 | #gray-line { 2 | background-color: #E0E0E0; 3 | height: 1px; 4 | width: 100%; 5 | } 6 | 7 | .resource-link { 8 | display: flex; 9 | align-items: center; 10 | gap: 8px; 11 | color:#0062fe 12 | 13 | } 14 | 15 | #transparent-button { 16 | width: 100%; 17 | background-color: Transparent; 18 | background-repeat:no-repeat; 19 | padding-bottom: 16px; 20 | padding-top: 16px; 21 | border: none; 22 | cursor:pointer; 23 | overflow: hidden; 24 | display: flex; 25 | flex-direction: column; 26 | justify-content: left; 27 | } 28 | 29 | a { 30 | background-color: crimson; 31 | width: 500px; 32 | } -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/badge/badge.component.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: "IBM Plex Sans", sans-serif; 3 | } 4 | 5 | #chart { 6 | width: 100%; 7 | height: 100%; 8 | margin: auto auto 50px auto; 9 | position: relative; 10 | } 11 | 12 | #chart ::ng-deep .axis { 13 | font-size: 58px; 14 | font-weight: 900; 15 | color: #525252; 16 | shape-rendering: geometricPrecision; 17 | } 18 | 19 | #chart ::ng-deep .total-score { 20 | font-size: 100px; 21 | fill: #525252; 22 | shape-rendering: geometricPrecision; 23 | } 24 | 25 | #chart ::ng-deep .percent-sign { 26 | font-size: 48px; 27 | shape-rendering: geometricPrecision; 28 | } 29 | 30 | #chart ::ng-deep .lateral-bar { 31 | fill: #525252; 32 | } 33 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HeaderComponent } from './header.component'; 4 | 5 | describe('HeaderComponent', () => { 6 | let component: HeaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [HeaderComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(HeaderComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/badge/badge.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BadgeComponent } from './badge.component'; 4 | 5 | describe('BadgeComponent', () => { 6 | let component: BadgeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [BadgeComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(BadgeComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/error/error.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ErrorComponent } from './error.component'; 4 | 5 | describe('ErrorComponent', () => { 6 | let component: ErrorComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ErrorComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ErrorComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/explorer/explorer.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |
7 |
8 |
9 |
Measure of Importance
10 | 11 |
12 |
13 |
14 |

Priority recommendations for improvements

15 | 20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /bin/brief_salutation: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | A script external to the package. 4 | """ 5 | 6 | __copyright__ = """ 7 | LICENSED INTERNAL CODE. PROPERTY OF IBM. 8 | IBM Research Licensed Internal Code 9 | (C) Copyright IBM Corp. 2025 10 | ALL RIGHTS RESERVED 11 | """ 12 | 13 | import click 14 | from tobefair_framework.complex_module.core import salutation 15 | 16 | 17 | @click.command() 18 | @click.argument("name") 19 | @click.option("--surname", default="", help="Write your surname") 20 | def main(name: str, surname: str): 21 | """Introduce yourself and salute.""" 22 | introduction = "My name is {} {}".format(name, surname) 23 | print(salutation()) 24 | print(introduction.strip()) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/legend/legend.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LegendComponent } from './legend.component'; 4 | 5 | describe('LegendComponent', () => { 6 | let component: LegendComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [LegendComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(LegendComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/result/result.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResultComponent } from './result.component'; 4 | 5 | describe('ResultComponent', () => { 6 | let component: ResultComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ResultComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ResultComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/details/details.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DetailsComponent } from './details.component'; 4 | 5 | describe('DetailsComponent', () => { 6 | let component: DetailsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [DetailsComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(DetailsComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair_backend/database/metadata_offering_methods.json: -------------------------------------------------------------------------------- 1 | { 2 | "META_TAGS": { 3 | "label": "HTML META Tags", 4 | "acronym": "meta_tags" 5 | }, 6 | "JSON_IN_HTML": { 7 | "label": "Embedded JSON-LD in HTML", 8 | "acronym": "json_in_html" 9 | }, 10 | "MICRODATA": { 11 | "label": "Microdata", 12 | "acronym": "microdata" 13 | }, 14 | "RDFA": { 15 | "label": "RDFa", 16 | "acronym": "rdfa" 17 | }, 18 | "TYPED_LINKS": { 19 | "label": "Typed Links", 20 | "acronym": "typed_links" 21 | }, 22 | "SIGNPOSTING": { 23 | "label": "Signposting Links", 24 | "acronym": "signposting" 25 | }, 26 | "CONTENT_NEGOTIATION": { 27 | "label": "Content Negotiation", 28 | "acronym": "content_negotiation" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ToBeFairComponent } from './to-be-fair.component'; 4 | 5 | describe('ToBeFairComponent', () => { 6 | let component: ToBeFairComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ToBeFairComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ToBeFairComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair_backend/database/metadata_formats.json: -------------------------------------------------------------------------------- 1 | { 2 | "HTML": { 3 | "label": "HTML", 4 | "acronym": "html" 5 | }, 6 | "XHTML": { 7 | "label": "XHTML", 8 | "acronym": "xhtml" 9 | }, 10 | "XML": { 11 | "label": "XML", 12 | "acronym": "xml" 13 | }, 14 | "RDF": { 15 | "label": "RDF", 16 | "acronym": "rdf" 17 | }, 18 | "RDFA": { 19 | "label": "RDFa", 20 | "acronym": "rdfa" 21 | }, 22 | "JSON": { 23 | "label": "JSON", 24 | "acronym": "json" 25 | }, 26 | "JSONLD": { 27 | "label": "JSON-LD", 28 | "acronym": "json-ld" 29 | }, 30 | "MICRODATA": { 31 | "label": "MICRODATA", 32 | "acronym": "microdata" 33 | }, 34 | "TEXT": { 35 | "label": "Text", 36 | "acronym": "text" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/evaluate/evaluate.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EvaluateComponent } from './evaluate.component'; 4 | 5 | describe('EvaluateComponent', () => { 6 | let component: EvaluateComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [EvaluateComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(EvaluateComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/explorer/explorer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ExplorerComponent } from './explorer.component'; 4 | 5 | describe('ExplorerComponent', () => { 6 | let component: ExplorerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ExplorerComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ExplorerComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/glossary/glossary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { GlossaryComponent } from './glossary.component'; 4 | 5 | describe('GlossaryComponent', () => { 6 | let component: GlossaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [GlossaryComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(GlossaryComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/models/fairness-evaluation.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { FAIRNotification } from "./FAIRnotification"; 5 | 6 | export interface FairnessEvaluation { 7 | evaluationId: string; 8 | 9 | evaluatedDigitalObjectID: string; 10 | evaluatedMetadataRecordID: string; 11 | evaluatedDigitalObjectLandingPageUrl: string; 12 | community: string; 13 | task: string; 14 | 15 | findability: number; 16 | accessibility: number; 17 | interoperability: number; 18 | reusability: number; 19 | totalScore: number; 20 | priorityRecommendations: Array; 21 | 22 | detailedResults: any; 23 | 24 | evaluatedMetadata: any; 25 | 26 | notifications: Array; 27 | } 28 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | clean: 18 | @-rm -rf $(BUILDDIR)/* 19 | @-rm -rf api/*.rst 20 | 21 | # Catch-all target: route all unknown targets to Sphinx using the new 22 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 23 | %: Makefile 24 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 25 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/user-guide/user-guide.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserGuideComponent } from './user-guide.component'; 4 | 5 | describe('UserGuideComponent', () => { 6 | let component: UserGuideComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [UserGuideComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(UserGuideComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/glossary/glossary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'lib-glossary', 6 | standalone: true, 7 | imports: [], 8 | templateUrl: './glossary.component.html', 9 | styleUrls: ['./glossary.component.css'], 10 | }) 11 | export class GlossaryComponent { 12 | constructor(private route: ActivatedRoute) {} 13 | ngAfterViewInit(): void { 14 | this.route.fragment.subscribe((fragment: string | null) => { 15 | if (fragment) { 16 | setTimeout(() => { 17 | document 18 | .getElementById(fragment) 19 | ?.scrollIntoView({ behavior: 'smooth' }); 20 | }, 0); 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **2BFAIR-framework version** 14 | 2BFAIR-framework version/tag/commit used. 15 | 16 | **Python version** 17 | Exact Python version used. E.g. 3.8.13 18 | 19 | **To reproduce** 20 | Steps to reproduce the behavior. 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | Make sure not to include any sensitive information. 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { HomeComponent } from './home.component'; 7 | 8 | describe('HomeComponent', () => { 9 | let component: HomeComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [HomeComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(HomeComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair_framework/tool_example/metadata_collector_schema_org_json_ld_simple.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from tobefair_framework.core.collector.metadata_collector import MetadataCollector 5 | from tobefair_framework.model.metadata.metadata_record import MetadataRecord 6 | 7 | 8 | class MetadataCollectorSchemaorgJsonldSimple(MetadataCollector): 9 | 10 | @classmethod 11 | def get_metadata_record( 12 | cls, raw_digital_object: str | dict 13 | ) -> MetadataRecord | None: 14 | if not isinstance(raw_digital_object, dict): 15 | raise Exception("raw_digital_object should be a dict.") 16 | return MetadataRecord( 17 | is_machine_retrieved=True, 18 | raw_value=raw_digital_object, 19 | ) 20 | -------------------------------------------------------------------------------- /tests/framework/test_configuration_file_dao.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from unittest import TestCase 5 | 6 | from tobefair_framework.core.configuration.fairness_configuration_file_dao import ( 7 | FAIRnessConfigurationFileDAO, 8 | ) 9 | from tobefair_framework.framework_constants import ( 10 | FAIRNESS_CONFIGURATION_FILE_PATH_FOR_THE_FRAMEWORK, 11 | ) 12 | 13 | 14 | class TestConfigurationFileDAO(TestCase): 15 | 16 | def test_read_file(self): 17 | fairness_configuration_dao = FAIRnessConfigurationFileDAO( 18 | file_path=FAIRNESS_CONFIGURATION_FILE_PATH_FOR_THE_FRAMEWORK 19 | ) 20 | fairness_configuration = fairness_configuration_dao.read_configuration() 21 | self.assertIsNotNone(fairness_configuration) 22 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/result-report/result-report.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResultReportComponent } from './result-report.component'; 4 | 5 | describe('ResultReportComponent', () => { 6 | let component: ResultReportComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ResultReportComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ResultReportComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/tool-glossary/tool-glossary.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ToolGlossaryComponent } from './tool-glossary.component'; 4 | 5 | describe('ToolGlossaryComponent', () => { 6 | let component: ToolGlossaryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ToolGlossaryComponent] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(ToolGlossaryComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/tool-glossary/tool-glossary.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ActivatedRoute } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'lib-tool-glossary', 6 | standalone: true, 7 | imports: [], 8 | templateUrl: './tool-glossary.component.html', 9 | styleUrl: './tool-glossary.component.css', 10 | }) 11 | export class ToolGlossaryComponent { 12 | constructor(private route: ActivatedRoute) {} 13 | ngAfterViewInit(): void { 14 | this.route.fragment.subscribe((fragment: string | null) => { 15 | if (fragment) { 16 | setTimeout(() => { 17 | document 18 | .getElementById(fragment) 19 | ?.scrollIntoView({ behavior: 'smooth' }); 20 | }, 0); 21 | } 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result/result.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { ResultComponent } from './result.component'; 7 | 8 | describe('ResultComponent', () => { 9 | let component: ResultComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [ResultComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(ResultComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/details/details.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { DetailsComponent } from './details.component'; 7 | 8 | describe('DetailsComponent', () => { 9 | let component: DetailsComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [DetailsComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(DetailsComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair_framework/core/evaluator/fairness_principle_evaluator.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import ClassVar 5 | 6 | from tobefair_framework.model.identifier.fair_principle_id import FAIRPrincipleID 7 | 8 | 9 | def evaluator_of_principle(principle: FAIRPrincipleID): 10 | def decorator(cls): 11 | EvaluatorRegistry.set_evaluator(cls) 12 | cls._fair_principle_to_evaluate = principle 13 | return cls 14 | 15 | return decorator 16 | 17 | 18 | class EvaluatorRegistry: 19 | _evaluators: ClassVar[list[type]] = [] 20 | 21 | @classmethod 22 | def set_evaluator(cls, evaluator: type): 23 | cls._evaluators.append(evaluator) 24 | 25 | @classmethod 26 | def get_evaluators(cls) -> list[type]: 27 | return cls._evaluators 28 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/explorer/explorer.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { ExplorerComponent } from './explorer.component'; 7 | 8 | describe('ExplorerComponent', () => { 9 | let component: ExplorerComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [ExplorerComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(ExplorerComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/glossary/glossary.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { GlossaryComponent } from './glossary.component'; 7 | 8 | describe('GlossaryComponent', () => { 9 | let component: GlossaryComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [GlossaryComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(GlossaryComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair-frontend/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import globals from "globals"; 2 | import pluginJs from "@eslint/js"; 3 | import tseslint from "typescript-eslint"; 4 | 5 | export default [ 6 | { files: ["**/*.{js,mjs,cjs,ts}"] }, 7 | { languageOptions: { globals: globals.browser } }, 8 | pluginJs.configs.recommended, 9 | ...tseslint.configs.recommended, 10 | { 11 | rules: { 12 | "no-undef": "error", 13 | "no-constant-binary-expression": "error", 14 | "no-dupe-else-if": "error", 15 | "no-duplicate-imports": "error", 16 | "no-unused-vars": "error", 17 | "no-var": "error", 18 | "no-useless-assignment": "error", 19 | "func-name-matching": "warn", 20 | "no-console": "warn", 21 | "no-empty": "error", 22 | "no-empty-function": "warn", 23 | "no-lone-blocks": "warn", 24 | }, 25 | }, 26 | ]; 27 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/user-guide/user-guide.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { UserGuideComponent } from './user-guide.component'; 7 | 8 | describe('UserGuideComponent', () => { 9 | let component: UserGuideComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [UserGuideComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(UserGuideComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair_framework/controller/configuration_controller.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from tobefair_framework.core.configuration.fairness_configuration_file_dao import ( 5 | FAIRnessConfigurationFileDAO, 6 | ) 7 | from tobefair_framework.framework_constants import ( 8 | FAIRNESS_CONFIGURATION_FILE_PATH_FOR_THE_FRAMEWORK, 9 | ) 10 | from tobefair_framework.model.configuration.fairness_configuration import ( 11 | FAIRnessConfiguration, 12 | ) 13 | 14 | 15 | class ConfigurationController: 16 | 17 | @classmethod 18 | def get_configuration(cls) -> FAIRnessConfiguration: 19 | fairness_configuration = FAIRnessConfigurationFileDAO( 20 | file_path=FAIRNESS_CONFIGURATION_FILE_PATH_FOR_THE_FRAMEWORK 21 | ) 22 | return fairness_configuration.read_configuration() 23 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/link-button/link-button.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { LinkButtonComponent } from './link-button.component'; 7 | 8 | describe('LinkButtonComponent', () => { 9 | let component: LinkButtonComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [LinkButtonComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(LinkButtonComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/result-report/result-report.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { ResultReportComponent } from './result-report.component'; 7 | 8 | describe('ResultReportComponent', () => { 9 | let component: ResultReportComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [ResultReportComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(ResultReportComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/tool-glossary/tool-glossary.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 5 | 6 | import { ToolGlossaryComponent } from './tool-glossary.component'; 7 | 8 | describe('ToolGlossaryComponent', () => { 9 | let component: ToolGlossaryComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async () => { 13 | await TestBed.configureTestingModule({ 14 | imports: [ToolGlossaryComponent] 15 | }) 16 | .compileComponents(); 17 | 18 | fixture = TestBed.createComponent(ToolGlossaryComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tobefair_framework/model/digital_object_info.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel, ConfigDict 5 | 6 | from tobefair_framework.model.identifier.identifier_info import ( 7 | IdentifierInfo, 8 | mocked_identifier_info, 9 | ) 10 | from tobefair_framework.model.landing_page import LandingPage 11 | from tobefair_framework.model.metadata.metadata_record import MetadataRecord 12 | 13 | 14 | class DigitalObjectInfo(BaseModel): 15 | model_config = ConfigDict(arbitrary_types_allowed=True) 16 | identifier_info: IdentifierInfo 17 | metadata_record: MetadataRecord | None 18 | landing_page: LandingPage | None 19 | 20 | 21 | def mock_digital_object_info() -> DigitalObjectInfo: 22 | return DigitalObjectInfo( 23 | identifier_info=mocked_identifier_info, metadata_record=None, landing_page=None 24 | ) 25 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/models/fairness-evaluation-api.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { FAIRNotification } from "./FAIRnotification"; 5 | 6 | export interface FairnessEvaluationAPI { 7 | overall_result: { 8 | evaluation_id: string; 9 | evaluated_digital_object_id: string; 10 | evaluated_metadata_record_id: string; 11 | task: string; 12 | community: string; 13 | evaluated_digital_object_landing_page_url: string; 14 | evaluation_score: { 15 | Findability: number; 16 | Accessibility: number; 17 | Interoperability: number; 18 | Reusability: number; 19 | total_score: number; 20 | }; 21 | priority_recommendations: Array; 22 | }; 23 | 24 | detailed_results: any; 25 | 26 | evaluated_metadata: any; 27 | 28 | notifications: Array; 29 | } 30 | -------------------------------------------------------------------------------- /tobefair_framework/core/notification/notifications_middleware.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import uuid 5 | 6 | from fastapi import Request 7 | from starlette.middleware.base import BaseHTTPMiddleware 8 | 9 | from tobefair_framework.core.notification.contexts import request_id_var 10 | from tobefair_framework.core.notification.notification_context import ( 11 | NotificationRegistry, 12 | ) 13 | 14 | 15 | class NotificationMiddleware(BaseHTTPMiddleware): 16 | async def dispatch(self, request: Request, call_next): 17 | request_id = str(uuid.uuid4()) 18 | context_token = request_id_var.set(request_id) 19 | try: 20 | response = await call_next(request) 21 | return response 22 | finally: 23 | NotificationRegistry.clear_notifications() 24 | request_id_var.reset(context_token) 25 | -------------------------------------------------------------------------------- /tobefair-frontend/scripts/build.sh: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | #!/bin/bash 5 | 6 | set -e # Exit on error. 7 | 8 | echo "travis_fold:start:Building angular application..." 9 | 10 | echo ================== 11 | echo == Creating app == 12 | echo ================== 13 | mkdir -p spl-app 14 | node main.js 15 | 16 | echo ============================= 17 | echo == Installing dependencies == 18 | echo ============================= 19 | cd spl-app 20 | npm install --legacy-peer-deps --cache=tmp 21 | 22 | # FIXME(kcsys4sd/dwb-ide#112): Added this dependency due to build errors. 23 | npm install @types/topojson-specification --legacy-peer-deps 24 | 25 | echo ========================== 26 | echo == Building application == 27 | echo ========================== 28 | npm run build -- --configuration=production --progress=false 29 | 30 | echo "travis_fold:end:Angular application built" 31 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /tobefair-frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | # See http://help.github.com/ignore-files/ for more about ignoring files. 4 | .env 5 | .DS_Store 6 | # Compiled output 7 | /dist 8 | /tmp 9 | /out-tsc 10 | /bazel-out 11 | 12 | # Node 13 | /node_modules 14 | npm-debug.log 15 | yarn-error.log 16 | 17 | # IDEs and editors 18 | .idea/ 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # Visual Studio Code 27 | .vscode/ 28 | .vscode/* 29 | !.vscode/settings.json 30 | !.vscode/tasks.json 31 | !.vscode/launch.json 32 | !.vscode/extensions.json 33 | .history/* 34 | 35 | # Miscellaneous 36 | /.angular/cache 37 | .sass-cache/ 38 | /connect.lock 39 | /coverage 40 | /libpeerconnection.log 41 | testem.log 42 | /typings 43 | 44 | # System files 45 | .DS_Store 46 | Thumbs.db 47 | 48 | #Custom 49 | .npmrc 50 | dev-config 51 | 52 | .nx/cache 53 | .nx/workspace-data 54 | -------------------------------------------------------------------------------- /tobefair_framework/core/configuration/fairness_configuration_file_dao.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | 6 | from pydantic import ValidationError 7 | 8 | from tobefair_framework.core.configuration.fairness_configuration_dao import ( 9 | FAIRnessConfigurationDAO, 10 | ) 11 | from tobefair_framework.model.configuration.fairness_configuration import ( 12 | FAIRnessConfiguration, 13 | ) 14 | 15 | 16 | class FAIRnessConfigurationFileDAO(FAIRnessConfigurationDAO): 17 | 18 | file_path: str 19 | 20 | def read_configuration(self) -> FAIRnessConfiguration: 21 | f = open(self.file_path) 22 | json_data = json.load(f) 23 | f.close() 24 | try: 25 | configuration = FAIRnessConfiguration() 26 | configuration.set_configuration(json_data=json_data) 27 | return configuration 28 | except ValidationError as e: 29 | raise Exception(e) 30 | -------------------------------------------------------------------------------- /tobefair_backend/constants.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | EVALUATORS_PACKAGE: str = "tobefair_backend.principle_evaluators" 5 | MAXIMUM_RESPONSE_SIZE = 1_000_000 6 | FILE_FORMAT_PATH = "tobefair_backend/database/file_formats.json" 7 | METADATA_FORMAT_PATH = "tobefair_backend/database/metadata_formats.json" 8 | METADATA_OFFERING_METHOD_PATH = ( 9 | "tobefair_backend/database/metadata_offering_methods.json" 10 | ) 11 | METADATA_SOURCE_PATH = "tobefair_backend/database/metadata_sources.json" 12 | METADATA_STANDARD_PATH = "tobefair_backend/database/metadata_standards.json" 13 | STANDARD_URI_PROTOCOL_PATH = "tobefair_backend/database/standard_uri_protocols.json" 14 | ACCESS_LEVEL_GROUP_PATH = "database/access_rights.json" 15 | SCHEMA_ORG_DATASET_TYPES = [ 16 | "dataset", 17 | "https://schema.org/dataset", 18 | "http://schema.org/dataset", 19 | ] 20 | FAIRNESS_CONFIGURATION_FILE_PATH = ( 21 | "./tobefair_backend/config/fairness_configuration.json" 22 | ) 23 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/evaluate/evaluate.component.css: -------------------------------------------------------------------------------- 1 | .container input { 2 | width: 100%; 3 | } 4 | 5 | :host div.outer { 6 | /* border-style: solid; 7 | border-color: blue; */ 8 | padding: 1em; 9 | } 10 | 11 | h2 { 12 | font-weight: normal; 13 | margin-block-start: 0em; 14 | margin-bottom: 16px; 15 | } 16 | 17 | input { 18 | border-radius: 0%; 19 | border: 1px solid lightgray; 20 | font-size: 14px; 21 | padding: 12px 12px; 22 | margin-top: 8px 23 | /* width: 97.5%; */ 24 | } 25 | 26 | input, 27 | select, 28 | textarea { 29 | box-sizing: border-box; 30 | -moz-box-sizing: border-box; 31 | -webkit-box-sizing: border-box; 32 | } 33 | 34 | ::placeholder { 35 | color: lightgray; 36 | opacity: 1; /* Firefox */ 37 | } 38 | 39 | label { 40 | color: gray; 41 | } 42 | 43 | .right-aligned { 44 | text-align: right; 45 | } 46 | 47 | a { 48 | color: black; 49 | text-decoration: none; 50 | } 51 | 52 | a:hover { 53 | cursor: pointer; 54 | color: #0062fe; 55 | } 56 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/result/result.component.css: -------------------------------------------------------------------------------- 1 | :host div.outer { 2 | /* border-style: solid; 3 | border-color: red; */ 4 | padding: 1em; 5 | position: relative; 6 | } 7 | 8 | .bold { 9 | font-weight: 500; 10 | } 11 | 12 | .grid-container { 13 | display: flex; 14 | justify-content: center; 15 | } 16 | 17 | #notifications-box{ 18 | position: absolute; 19 | top: 0; 20 | right: 0; 21 | z-index: 1; /* Ensure it's on top */ 22 | display: flex; 23 | flex-direction: column; 24 | padding: 16px; 25 | gap: 16px; 26 | } 27 | 28 | h2 { 29 | font-weight: normal; 30 | margin-block-start: 0em; 31 | } 32 | 33 | hr { 34 | height: 1.5px; 35 | background-color: black; 36 | border: none; 37 | margin-left: -1em; /* Subtracting from margin to offset the padding that */ 38 | margin-right: -1em; /* comes from element :host div.outer */ 39 | } 40 | 41 | a { 42 | color: black; 43 | text-decoration: none; 44 | } 45 | 46 | a:hover { 47 | cursor: pointer; 48 | color: #0062fe; 49 | } 50 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { CommonModule } from '@angular/common'; 5 | import { Component } from '@angular/core'; 6 | import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router'; 7 | import { HeaderModule, ThemeModule } from 'carbon-components-angular'; 8 | 9 | import { ResultComponent } from './result/result.component'; 10 | import { GlossaryComponent } from './glossary/glossary.component'; 11 | import { ExplorerComponent } from './explorer/explorer.component'; 12 | @Component({ 13 | selector: 'app-root', 14 | standalone: true, 15 | imports: [ 16 | CommonModule, 17 | RouterOutlet, 18 | RouterLink, 19 | RouterLinkActive, 20 | ResultComponent, 21 | GlossaryComponent, 22 | ExplorerComponent, 23 | HeaderModule, 24 | ThemeModule, 25 | ], 26 | templateUrl: './app.component.html', 27 | styleUrl: './app.component.css', 28 | }) 29 | export class AppComponent { 30 | title = '2BFAIR'; 31 | } 32 | -------------------------------------------------------------------------------- /tobefair_backend/model/file_format.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import List 5 | 6 | from pydantic import BaseModel, ValidationError, field_validator 7 | 8 | from tobefair_backend.model.resources.data_record import DataType 9 | 10 | 11 | class FileFormat(BaseModel): 12 | ext: List[str] 13 | name: str 14 | mime: List[DataType] 15 | reason: List[str] 16 | source: List[str] 17 | 18 | @field_validator("mime", mode="before") 19 | @classmethod 20 | def validate_mime(cls, value): 21 | if isinstance(value, list): 22 | if all([isinstance(item, str) for item in value]): 23 | return [DataType(value=item) for item in value] 24 | if all([isinstance(item, DataType) for item in value]): 25 | return value 26 | raise ValidationError 27 | 28 | 29 | def mime_types(formats: List[FileFormat]) -> List[DataType]: 30 | acc = [] 31 | [acc := acc + format.mime for format in formats] 32 | return acc 33 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/public-api.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | /* 5 | * Public API Surface of to-be-fair 6 | */ 7 | 8 | export * from './lib/to-be-fair.service'; 9 | export * from './lib/to-be-fair.component'; 10 | export * from './lib/to-be-fair.module'; 11 | 12 | export * from './lib/badge/badge.component'; 13 | export * from './lib/result/result.component'; 14 | export * from './lib/header/header.component'; 15 | export * from './lib/details/details.component'; 16 | export * from './lib/explorer/explorer.component'; 17 | export * from './lib/glossary/glossary.component'; 18 | export * from './lib/env-var.guard'; 19 | export * from './lib/evaluation.service'; 20 | export * from './models/fairness-evaluation'; 21 | export * from './models/fairness-evaluation-api'; 22 | export * from './lib/error/error.component'; 23 | export * from './lib/tool-glossary/tool-glossary.component'; 24 | export * from './lib/user-guide/user-guide.component'; 25 | export * from './lib/result-report/result-report.component'; 26 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # configuration approach followed: 2 | # - whenever possible, prefer pyproject.toml 3 | # - for configurations insufficiently supported by pyproject.toml, use setup.cfg instead 4 | # - setup.py discouraged; minimal stub included only for compatibility with legacy tools 5 | 6 | # pyproject.toml support for configs outside PEP 621 is currently only in beta 7 | # see https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html 8 | [options] 9 | packages = find: 10 | include_package_data = False 11 | # non-endpoint scripts are not supported in pyproject.toml 12 | scripts = 13 | bin/brief_salutation 14 | bin/a_shell_script 15 | 16 | [options.package_data] 17 | tobefair_framework = py.typed 18 | 19 | [options.packages.find] 20 | exclude = 21 | # the following exclusion is to prevent shipping of tests. 22 | # if you do include them, add pytest to the required packages. 23 | *tests* 24 | 25 | # flake8 currently does not support pyproject.toml 26 | # see https://github.com/PyCQA/flake8/issues/234 27 | [flake8] 28 | max-line-length = 80 29 | ignore = E203, E501, W503 30 | -------------------------------------------------------------------------------- /tobefair_framework/model/configuration/fair_principle_configuration.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import Dict, List 5 | 6 | from pydantic import BaseModel 7 | 8 | from tobefair_framework.model.composite.identifiable_composite import ( 9 | IdentifiableComposite, 10 | ) 11 | from tobefair_framework.model.configuration.fairness_metric_configuration import ( 12 | FAIRnessMetricConfiguration, 13 | ) 14 | from tobefair_framework.model.identifier.fair_principle_id import FAIRPrincipleID 15 | from tobefair_framework.model.identifier.fairness_metric_id import FAIRnessMetricID 16 | 17 | 18 | class FAIRPrincipleConfiguration( 19 | BaseModel, IdentifiableComposite[FAIRnessMetricConfiguration] 20 | ): 21 | id: FAIRPrincipleID 22 | name: str 23 | metrics: Dict[FAIRnessMetricID, FAIRnessMetricConfiguration] 24 | 25 | @property 26 | def get_id(self) -> FAIRPrincipleID: 27 | return self.id 28 | 29 | def get_children(self) -> List[FAIRnessMetricConfiguration]: 30 | return list(self.metrics.values()) 31 | -------------------------------------------------------------------------------- /tobefair-frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "outDir": "./dist/out-tsc", 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "skipLibCheck": true, 13 | "esModuleInterop": true, 14 | "sourceMap": true, 15 | "declaration": false, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "paths": { 23 | "@dwb/to-be-fair": ["./projects/to-be-fair/src/public-api.ts"] 24 | }, 25 | "lib": ["ES2022", "dom"] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/README.md: -------------------------------------------------------------------------------- 1 | # ToBeFair 2 | 3 | This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.0.0. 4 | 5 | ## Code scaffolding 6 | 7 | Run `ng generate component component-name --project to-be-fair` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project to-be-fair`. 8 | > Note: Don't forget to add `--project to-be-fair` or else it will be added to the default project in your `angular.json` file. 9 | 10 | ## Build 11 | 12 | Run `ng build to-be-fair` to build the project. The build artifacts will be stored in the `dist/` directory. 13 | 14 | ## Publishing 15 | 16 | After building your library with `ng build to-be-fair`, go to the dist folder `cd dist/to-be-fair` and run `npm publish`. 17 | 18 | ## Running unit tests 19 | 20 | Run `ng test to-be-fair` to execute the unit tests via [Karma](https://karma-runner.github.io). 21 | 22 | ## Further help 23 | 24 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 25 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/carbon/carbon.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | 3 | import { 4 | ButtonModule, 5 | CheckboxModule, 6 | ContentSwitcherModule, 7 | DropdownModule, 8 | IconModule, 9 | IconService, 10 | InlineLoadingModule, 11 | InputModule, 12 | ModalModule, 13 | NumberModule, 14 | ProgressIndicatorModule, 15 | RadioModule, 16 | SelectModule, 17 | SliderModule, 18 | TableModule, 19 | TagModule, 20 | TilesModule, 21 | ToggleModule, 22 | } from 'carbon-components-angular'; 23 | 24 | const carbonModules = [ 25 | ButtonModule, 26 | CheckboxModule, 27 | ContentSwitcherModule, 28 | DropdownModule, 29 | IconModule, 30 | InputModule, 31 | InlineLoadingModule, 32 | ModalModule, 33 | ProgressIndicatorModule, 34 | SliderModule, 35 | NumberModule, 36 | ProgressIndicatorModule, 37 | RadioModule, 38 | SelectModule, 39 | SliderModule, 40 | TableModule, 41 | TagModule, 42 | TilesModule, 43 | ToggleModule, 44 | ]; 45 | 46 | @NgModule({ 47 | imports: carbonModules, 48 | exports: carbonModules, 49 | }) 50 | export class CarbonModule {} 51 | -------------------------------------------------------------------------------- /tobefair_backend/repository/uri_protocol_repository.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | from typing import ClassVar, List 6 | 7 | from tobefair_backend.constants import STANDARD_URI_PROTOCOL_PATH 8 | from tobefair_backend.model.uri_protocol import URIProtocol 9 | 10 | 11 | class URIProtocolRepository: 12 | _all: ClassVar[List[URIProtocol] | None] = None 13 | 14 | @classmethod 15 | def all(cls) -> List[URIProtocol]: 16 | if cls._all is None: 17 | path = STANDARD_URI_PROTOCOL_PATH 18 | with open(path, "r") as file: 19 | json_string = file.read() 20 | json_dict = json.loads(json_string) 21 | cls._all = [ 22 | uri_protocol 23 | for protocol_dict in json_dict 24 | if ( 25 | uri_protocol := URIProtocol.model_validate_json( 26 | json.dumps(protocol_dict) 27 | ) 28 | ) 29 | ] 30 | return cls._all 31 | return cls._all 32 | -------------------------------------------------------------------------------- /tobefair_framework/model/composite/leaf_result.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import Dict, List, Self 5 | 6 | from tobefair_framework.model.composite.identifiable_composite_result import ( 7 | IdentifiableCompositeResult, 8 | ) 9 | 10 | 11 | class LeafResult(IdentifiableCompositeResult["LeafResult"]): 12 | def get_children(self) -> list["LeafResult"]: 13 | return [self] 14 | 15 | def sort_all(self): 16 | self.sort_results() 17 | 18 | def get_last_children(self) -> list["LeafResult"]: 19 | return [self] 20 | 21 | @classmethod 22 | def from_results( 23 | cls, results: List["LeafResult"], general_configuration: Dict 24 | ) -> List[Self]: 25 | return [] 26 | 27 | def get_results(self) -> Dict: 28 | return {} 29 | 30 | def set_results(self, value): 31 | return 32 | 33 | @classmethod 34 | def _from_configuration_and_results( 35 | cls, configuration, results: List["LeafResult"] 36 | ) -> Self: 37 | return super()._from_configuration_and_results(configuration, results) 38 | -------------------------------------------------------------------------------- /tobefair_framework/model/identifier/id.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from abc import ABC, abstractmethod 5 | from typing import Generic, TypeVar 6 | 7 | RawValue = TypeVar("RawValue", covariant=True) 8 | 9 | 10 | class ID(ABC, Generic[RawValue]): 11 | 12 | @property 13 | @abstractmethod 14 | def raw_value(self) -> RawValue: 15 | pass 16 | 17 | @abstractmethod 18 | def __lt__(self, other) -> bool: 19 | pass 20 | 21 | 22 | class SerialHierarchicalID(ID[RawValue]): 23 | @abstractmethod 24 | def get_parent_id(self) -> ID: 25 | pass 26 | 27 | def __lt__(self, other) -> bool: 28 | if isinstance(other, SerialHierarchicalID): 29 | return self.raw_value < other.raw_value 30 | return False 31 | 32 | def is_descendant_of(self, ancestor: ID, generations: int) -> bool: 33 | descendant: ID = self 34 | while generations > 0 and isinstance(descendant, SerialHierarchicalID): 35 | descendant = descendant.get_parent_id() 36 | generations -= 1 37 | return descendant == ancestor 38 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { TestBed } from '@angular/core/testing'; 5 | import { AppComponent } from './app.component'; 6 | 7 | describe('AppComponent', () => { 8 | beforeEach(async () => { 9 | await TestBed.configureTestingModule({ 10 | imports: [AppComponent], 11 | }).compileComponents(); 12 | }); 13 | 14 | it('should create the app', () => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.componentInstance; 17 | expect(app).toBeTruthy(); 18 | }); 19 | 20 | it(`should have the 'frontend' title`, () => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.componentInstance; 23 | expect(app.title).toEqual('frontend'); 24 | }); 25 | 26 | it('should render title', () => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.nativeElement as HTMLElement; 30 | expect(compiled.querySelector('h1')?.textContent).toContain('Hello, frontend'); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: 4 | 5 | ## How do I report a bug or suggest an enhancement? 6 | 7 | - As a first step, please search in the [existing issues](https://github.ibm.com/brl-kbe/2BFAIR-framework/issues?q=is%3Aissue) 8 | to check if your point has already been addressed. 9 | - If that is not the case, go ahead and [create an issue](https://github.ibm.com/brl-kbe/2BFAIR-framework/issues/new/choose) 10 | of the respective type, providing the details as instructed in the template. 11 | 12 | ## How do I submit a change? 13 | 14 | We welcome contributions via pull requests: 15 | - Fork the repo and create your branch from the default branch 16 | - If you have added code that should be tested, add tests 17 | - If any documentation updates are needed, make them 18 | - Ensure the test suite passes and the code lints 19 | - Submit the pull request 20 | 21 | Once you have submitted your PR: 22 | - Note that a PR is considered for review only if Travis CI builds successfully 23 | - Upon approval, PR is to be merged using the "squash and merge" option, so that the commit history remains linear and readable 24 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/recommendation-list/recommendation-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { RouterLink, RouterLinkActive } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'lib-recommendation-list', 6 | standalone: true, 7 | imports: [RouterLink, RouterLinkActive], 8 | templateUrl: './recommendation-list.component.html', 9 | styleUrl: './recommendation-list.component.css', 10 | }) 11 | export class RecommendationListComponent { 12 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 13 | @Input() recommendations!: Array; 14 | @Input() length: number = 5; 15 | @Input() redirect_ref?: string; 16 | should_display_redirect: boolean = true; 17 | @Input() useSeeMore = true; 18 | 19 | ngOnInit(): void { 20 | this.should_display_redirect = this.recommendations.length > this.length; 21 | this.recommendations = this.recommendations.slice(0, this.length); 22 | } 23 | 24 | ngAfterViewInit(): void { 25 | if (this.useSeeMore == false) { 26 | const link = document.getElementById('seeMore'); 27 | if (link) { 28 | link.style.display = 'none'; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tobefair_framework/model/recommendation.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from pydantic import BaseModel, model_serializer 5 | 6 | from tobefair_framework.model.identifier.fairness_test_id import FAIRnessTestID 7 | 8 | 9 | class Recommendation(BaseModel): 10 | priority: int = 0 11 | value: str 12 | 13 | @model_serializer 14 | def ser_model(self) -> str: 15 | return self.value 16 | 17 | def add_test_id_prefix(self, test_id: FAIRnessTestID) -> "Recommendation": 18 | copy = self.model_copy() 19 | copy.value = f"{test_id.value}: {self.value}" 20 | return copy 21 | 22 | @classmethod 23 | def get_priority_recommendations( 24 | cls, number_of_recommendations: int, recommendations: list["Recommendation"] 25 | ) -> list["Recommendation"]: 26 | recommendations_sorted_by_priority = sorted( 27 | recommendations, key=lambda recommendation: recommendation.priority 28 | ) 29 | if len(recommendations_sorted_by_priority) < number_of_recommendations: 30 | return recommendations_sorted_by_priority 31 | return recommendations_sorted_by_priority[:number_of_recommendations] 32 | -------------------------------------------------------------------------------- /tobefair_backend/model/response_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from http.client import HTTPResponse 5 | from io import BytesIO 6 | 7 | from tobefair_backend.model.resources.data_size import DataSize 8 | 9 | 10 | class ResponseWrapper: 11 | 12 | def __init__(self, http_response: HTTPResponse, maximum_response_size: int): 13 | self.http_response = http_response 14 | self.file_buffer = self.make_response_file_buffer(maximum_response_size) 15 | 16 | def get_response_file_buffer(self) -> BytesIO: 17 | return self.file_buffer 18 | 19 | def make_response_file_buffer(self, max_response_size: int) -> BytesIO: 20 | file_buffer = BytesIO() 21 | data_record_content = self.http_response.read(max_response_size) 22 | file_buffer.write(data_record_content) 23 | return file_buffer 24 | 25 | def get_response_content_size(self, max_response_size: int) -> DataSize: 26 | with self.get_response_file_buffer() as response_file_buffer: 27 | size = DataSize(value=response_file_buffer.getbuffer().nbytes) 28 | return size 29 | 30 | @property 31 | def wrapped_value(self) -> HTTPResponse: 32 | return self.http_response 33 | -------------------------------------------------------------------------------- /tobefair_framework/tool_example/digital_object_collector_from_file.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | 6 | from tobefair_framework.core.collector.digital_object_collector import ( 7 | DigitalObjectCollector, 8 | ) 9 | from tobefair_framework.core.collector.metadata_collector import MetadataCollector 10 | from tobefair_framework.model.digital_object_info import DigitalObjectInfo 11 | from tobefair_framework.model.identifier.identifier_info import IdentifierInfo 12 | 13 | 14 | class DigitalObjectCollectorFromFile(DigitalObjectCollector): 15 | 16 | file_path: str 17 | 18 | def _read_digital_object_info( 19 | self, 20 | identifier_info: IdentifierInfo, 21 | metadata_collector: MetadataCollector, 22 | ) -> DigitalObjectInfo: 23 | with open(self.file_path, "r") as file: 24 | digital_object_dict = json.load(file) 25 | metadata_record = metadata_collector.get_metadata_record( 26 | raw_digital_object=digital_object_dict 27 | ) 28 | return DigitalObjectInfo( 29 | identifier_info=identifier_info, 30 | metadata_record=metadata_record, 31 | landing_page=None, 32 | ) 33 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/env-var.guard.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ActivatedRouteSnapshot, 3 | CanActivate, 4 | RouterStateSnapshot, 5 | UrlTree, 6 | } from '@angular/router'; 7 | import { Injectable } from '@angular/core'; 8 | import { HttpClient, HttpHeaders } from '@angular/common/http'; 9 | import { firstValueFrom, Observable } from 'rxjs'; 10 | 11 | @Injectable({ 12 | providedIn: 'root', 13 | }) 14 | export class EnvVarGuard implements CanActivate { 15 | public backendUrl = ''; 16 | 17 | constructor(private _httpClient: HttpClient) { 18 | // Empty. 19 | } 20 | 21 | canActivate( 22 | route: ActivatedRouteSnapshot, 23 | state_: RouterStateSnapshot, 24 | ): 25 | | Observable 26 | | Promise 27 | | boolean 28 | | UrlTree { 29 | const urlWithParams = `/get-backend`; 30 | 31 | return firstValueFrom( 32 | this._httpClient.get(urlWithParams, { 33 | responseType: 'text' as 'json', 34 | }), 35 | ) 36 | .then((value) => { 37 | console.log(value); 38 | this.backendUrl = value; 39 | return true; 40 | }) 41 | .catch((err) => { 42 | console.error('Erro na requisição:', err); 43 | return true; 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/header/header.component.css: -------------------------------------------------------------------------------- 1 | :host div.outer { 2 | padding: 1em; 3 | top: 85px; 4 | background-color: transparent; 5 | z-index: 200; 6 | } 7 | 8 | .grid-container { 9 | display: grid; 10 | grid-template-columns: 2fr 1fr; 11 | background: linear-gradient(#000, #000) center/1.5px 100% no-repeat; 12 | grid-gap: 16px; 13 | margin: 5px; 14 | background-position: 65% 0; 15 | } 16 | 17 | h2 { 18 | font-weight: normal; 19 | margin-block-start: 0em; 20 | font-size: 24px; 21 | } 22 | 23 | h3 { 24 | font-weight: normal; 25 | margin-block-start: 0em; 26 | font-size: 20px; 27 | } 28 | 29 | hr { 30 | height: 1.5px; 31 | background-color: #161616; 32 | border: none; 33 | margin-left: -1em; /* Subtracting from margin to offset the padding that */ 34 | margin-right: -1em; /* comes from element :host div.outer */ 35 | } 36 | 37 | #download { 38 | margin-bottom: 15px; 39 | } 40 | #download a { 41 | font-size: 12px; 42 | display: flex; 43 | align-items: center; 44 | color: black; 45 | } 46 | 47 | #download a:hover, 48 | svg:hover { 49 | cursor: pointer; 50 | color: #0062fe; 51 | fill: #0062fe; 52 | } 53 | 54 | a { 55 | color: black; 56 | text-decoration: none; 57 | } 58 | 59 | a:hover { 60 | cursor: pointer; 61 | color: #0062fe; 62 | } 63 | -------------------------------------------------------------------------------- /tobefair-frontend/server/server.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | const express = require("express"); 5 | const path = require("path"); 6 | const cors = require("cors"); 7 | 8 | const angularFilesDirectory = path.join( 9 | __dirname, 10 | "..", 11 | "dist", 12 | "frontend", 13 | "browser" 14 | ); 15 | 16 | // create a new express server 17 | const app = express(); 18 | 19 | app.use(cors()); 20 | 21 | app.get("/get-backend", (req, res) => { 22 | res.send(process.env.BACKEND_URL ?? "http://localhost:8000"); 23 | }); 24 | 25 | // serve the files out of root dir as our main files 26 | // (server.js should be copied to the dist folder BEFORE pushing to Bluemix) 27 | app.use(express.static(angularFilesDirectory)); 28 | 29 | // For all GET requests, send back index.html 30 | // so that PathLocationStrategy can be used 31 | app.get("/*", (req, res) => { 32 | const filepath = path.join(angularFilesDirectory, "index.html"); 33 | res.sendFile(filepath); 34 | }); 35 | 36 | const SERVER = "0.0.0.0"; 37 | const PORT = process.env.PORT || 42000; 38 | 39 | // start server on the specified port and binding host 40 | app.listen(PORT, SERVER, () => { 41 | // print a message when the server starts listening 42 | console.log(`server starting on ${SERVER}:${PORT}`); 43 | }); 44 | -------------------------------------------------------------------------------- /tobefair_backend/model/response_header_wrapper.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from http.client import HTTPMessage 5 | 6 | from tobefair_backend.model.resources.data_size import DataSize, DataType 7 | 8 | 9 | class ResponseHeaderWrapper: 10 | 11 | def __init__(self, wrapped_response_header: HTTPMessage): 12 | self._wrapped_value = wrapped_response_header 13 | 14 | def get_header_content_size(self, max_download_size: int) -> DataSize | None: 15 | if content_length := ( 16 | self._wrapped_value.get("content-length") 17 | or self._wrapped_value.get("Content-Length") 18 | ): 19 | try: 20 | return DataSize(value=int(content_length.split(";")[0])) 21 | except Exception: 22 | return DataSize(value=max_download_size) 23 | return None 24 | 25 | def get_header_content_type(self) -> DataType | None: 26 | if content_type := ( 27 | self._wrapped_value.get("content-type") 28 | or self._wrapped_value.get("Content-Type") 29 | ): 30 | return DataType(value=content_type.split(";")[0]) 31 | return None 32 | 33 | @property 34 | def wrapped_value(self) -> HTTPMessage: 35 | return self._wrapped_value 36 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/user-guide/user-guide.component.css: -------------------------------------------------------------------------------- 1 | * { 2 | scroll-behavior: smooth; 3 | } 4 | 5 | :host div.outer { 6 | padding: 1em; 7 | } 8 | /* Heading styles */ 9 | h2 { 10 | font-weight: normal; 11 | margin-block-start: 0; 12 | } 13 | 14 | h3 { 15 | font-weight: normal; 16 | } 17 | 18 | .pages { 19 | margin: 48px; 20 | } 21 | 22 | .step-by-step { 23 | margin: 32px; 24 | } 25 | ol { 26 | list-style-type: decimal; 27 | } 28 | 29 | img { 30 | width: 70%; 31 | margin: 25px; 32 | display: block; 33 | border: black solid 1px; 34 | } 35 | 36 | li { 37 | margin: 8px; 38 | } 39 | 40 | .inner-list { 41 | list-style-type: lower-alpha; 42 | margin: 16px; 43 | } 44 | 45 | #status { 46 | display: flex; 47 | align-items: center; 48 | justify-content: space-around; 49 | } 50 | 51 | #status img { 52 | height: 50px; 53 | } 54 | 55 | .image-auto { 56 | width: auto; 57 | } 58 | 59 | .image-margin-10 { 60 | margin: 10px; 61 | } 62 | 63 | a:hover { 64 | color: #0f62fe; 65 | text-decoration: none; 66 | } 67 | 68 | a { 69 | color: black; 70 | text-decoration: none; 71 | } 72 | 73 | /*Styles to create a space above the id*/ 74 | [id]:before { 75 | content: ""; 76 | display: block; 77 | height: 50px; 78 | margin-top: -50px; /* Invert the space above the link destination*/ 79 | visibility: hidden; 80 | } 81 | -------------------------------------------------------------------------------- /tobefair_backend/repository/json_dictionary_repository.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | from abc import ABC, abstractmethod 6 | from typing import Generic, List, TypeVar 7 | 8 | from pydantic import BaseModel 9 | 10 | T = TypeVar("T", bound=BaseModel) 11 | 12 | 13 | class JsonDictionaryRepository(ABC, Generic[T]): 14 | _all: List[T] | None = None 15 | 16 | @classmethod 17 | @abstractmethod 18 | def file_path(cls) -> str: 19 | pass 20 | 21 | @classmethod 22 | @abstractmethod 23 | def dictionary_to_model(cls, dictionary: dict) -> T | None: 24 | pass 25 | 26 | @classmethod 27 | def parse_json(cls, json_string: str) -> List[T]: 28 | json_file_dictionary = json.loads(json_string) 29 | return [ 30 | metadata_format 31 | for metadata_format in [ 32 | cls.dictionary_to_model(value) 33 | for value in list(json_file_dictionary.values()) 34 | ] 35 | if metadata_format is not None 36 | ] 37 | 38 | @classmethod 39 | def all(cls) -> List[T]: 40 | if cls._all is None: 41 | with open(cls.file_path(), "r") as json_file: 42 | cls._all = cls.parse_json(json_file.read()) 43 | return cls._all 44 | return cls._all 45 | -------------------------------------------------------------------------------- /tobefair_backend/database/standard_uri_protocols.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Advanced Message Queuing Protocol", 4 | "id": "amqp" 5 | }, 6 | { 7 | "name": "Constrained Application Protocol", 8 | "id": "coap" 9 | }, 10 | { 11 | "name": "Constrained Application Protocol Secure", 12 | "id": "coaps" 13 | }, 14 | { 15 | "name": "File Transfer Protocol", 16 | "id": "ftp" 17 | }, 18 | { 19 | "name": "Hyper Text Transfer Protocol", 20 | "id": "http" 21 | }, 22 | { 23 | "name": "Hyper Text Transfer Protocol Secure", 24 | "id": "https" 25 | }, 26 | { 27 | "name": "Message Queuing Telemetry Transport", 28 | "id": "mqtt" 29 | }, 30 | { 31 | "name": "Real Time Streaming Protocol", 32 | "id": "rtsp" 33 | }, 34 | { 35 | "name": "Real Time Streaming Protocol", 36 | "id": "rtspu" 37 | }, 38 | { 39 | "name": "Secure File Transfer Protocol", 40 | "id": "sftp" 41 | }, 42 | { 43 | "name": "Secure Hypertext Transfer Protocol", 44 | "id": "shttp" 45 | }, 46 | { 47 | "name": "Secure Shell", 48 | "id": "ssh" 49 | }, 50 | { 51 | "name": "Subversion", 52 | "id": "svn" 53 | }, 54 | { 55 | "name": "Telnet", 56 | "id": "telnet" 57 | }, 58 | { 59 | "name": "WebSocket", 60 | "id": "ws" 61 | }, 62 | { 63 | "name": "WebSocket Secure", 64 | "id": "wss" 65 | } 66 | ] 67 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/result-report/result-report.component.html: -------------------------------------------------------------------------------- 1 | 4 |
5 |

2BFAIR

6 |

2BFAIR FAIRness Evaluation Report

7 |

8 | 9 |

Overall Result

10 |

11 | This part shows the FAIRness, a percentage grade indicating how close a 12 | digital object is to fully abiding by the FAIR Principles, of your data. 13 |

14 | 15 |

Result by metric

16 |

17 | This part shows the results divided by the metrics of each dimension and how 18 | much was achieved in each one. 19 |

20 | 25 |

Detailed results

26 |

27 | This part is divided into principles. Each principle is divided by metrics. 28 | Each metric is divided into tests. In each test, it explains the test 29 | result, the score obtained, the maturity of each metric, a recommendation 30 | and what the person loses if they do not pass this test. 31 |

32 | 33 |
34 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/to-be-fair.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | import { ResultComponent } from './result/result.component'; 4 | import { GlossaryComponent } from './glossary/glossary.component'; 5 | import { ExplorerComponent } from './explorer/explorer.component'; 6 | import { DetailsComponent } from './details/details.component'; 7 | import { ToolGlossaryComponent } from './tool-glossary/tool-glossary.component'; 8 | import { ResultReportComponent } from './result-report/result-report.component'; 9 | 10 | export const routes: Routes = [ 11 | { 12 | path: 'result', 13 | component: ResultComponent, 14 | title: 'Evaluation Result', 15 | }, 16 | { 17 | path: 'explorer', 18 | component: ExplorerComponent, 19 | title: 'Explore Results', 20 | }, 21 | { 22 | path: 'details', 23 | component: DetailsComponent, 24 | title: 'Detail Results', 25 | }, 26 | { 27 | path: 'glossary', 28 | component: GlossaryComponent, 29 | title: 'Glossary', 30 | }, 31 | { 32 | path: 'tool-glossary', 33 | component: ToolGlossaryComponent, 34 | title: 'Tool Glossary', 35 | }, 36 | { 37 | path: 'result-report', 38 | component: ResultReportComponent, 39 | title: 'Full Report', 40 | }, 41 | // { 42 | // path: '**', component: PageNotFoundComponent, // TODO: Wildcard route for a 404 page 43 | // }, 44 | ]; 45 | -------------------------------------------------------------------------------- /tobefair_backend/repository/metadata_offering_method_repository.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from tobefair_backend.constants import METADATA_OFFERING_METHOD_PATH 5 | from tobefair_backend.repository.json_dictionary_repository import ( 6 | JsonDictionaryRepository, 7 | ) 8 | from tobefair_framework.model.metadata.metadata_offering_method import ( 9 | MetadataOfferingMethod, 10 | ) 11 | 12 | 13 | class MetadataOfferingMethodRepository( 14 | JsonDictionaryRepository[MetadataOfferingMethod] 15 | ): 16 | 17 | @classmethod 18 | def file_path(cls) -> str: 19 | return METADATA_OFFERING_METHOD_PATH 20 | 21 | @classmethod 22 | def dictionary_to_model(cls, dictionary: dict) -> MetadataOfferingMethod | None: 23 | try: 24 | return MetadataOfferingMethod.model_validate(dictionary) 25 | except Exception: 26 | return None 27 | 28 | @classmethod 29 | def get_metadata_metadata_offering_method( 30 | cls, acronym: str 31 | ) -> MetadataOfferingMethod | None: 32 | 33 | matching_offering_method: MetadataOfferingMethod | None = None 34 | [ 35 | (matching_offering_method := offering_method) 36 | for offering_method in cls.all() 37 | if offering_method.acronym.upper() == acronym.upper() 38 | ] 39 | return matching_offering_method 40 | -------------------------------------------------------------------------------- /tobefair_backend/model/resources/typed_link.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import ClassVar, List 5 | 6 | from pydantic import BaseModel, PrivateAttr 7 | 8 | from tobefair_backend.model.resources.data_size import DataSize, DataType 9 | 10 | 11 | class TypedLink(BaseModel): 12 | href: str 13 | rel: str | None = None 14 | type: DataType | None = None 15 | profile: str | None = None 16 | content_size: DataSize | None = None 17 | measured_variable: List[str] | str | None = None 18 | 19 | _accepted_rel_types: ClassVar[List[str]] = PrivateAttr( 20 | [ 21 | "meta", 22 | "alternate meta", 23 | "metadata", 24 | "collection", 25 | "author", 26 | "describes", 27 | "item", 28 | "type", 29 | "search", 30 | "alternate", 31 | "describedby", 32 | "cite-as", 33 | "linkset", 34 | "license", 35 | ] 36 | ) 37 | 38 | def __eq__(self, value: object) -> bool: 39 | if isinstance(value, TypedLink): 40 | return self.href == value.href 41 | return False 42 | 43 | def __hash__(self) -> int: 44 | return hash(self.href) 45 | 46 | @classmethod 47 | def rel_type_is_accepted(cls, typed_link: "TypedLink"): 48 | return typed_link.rel in cls._accepted_rel_types 49 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/evaluate/evaluate.component.html: -------------------------------------------------------------------------------- 1 |
2 |

FAIRness Evaluation

3 | 4 |
10 | 11 | 18 | 19 |
20 |
21 | 22 | 45 | 46 |
47 | 50 |
51 |
52 |
53 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

5 | Evaluated 6 | resource: 7 |

8 | {{ digitalObjectLandingPageUrl }} 15 |
16 |
17 | 22 | 33 |
34 |
35 | 36 |

Overall:

37 | 42 |
43 |
44 |
45 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /tobefair_backend/service/main.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from fastapi import FastAPI 5 | from fastapi.middleware.cors import CORSMiddleware 6 | 7 | from tobefair_backend.service.routes.check_app_routes import check_app_router 8 | from tobefair_backend.service.routes.configuration_routes import configuration_router 9 | from tobefair_backend.service.routes.evaluation_routes import evaluation_router 10 | from tobefair_framework.core.notification.notifications_middleware import ( 11 | NotificationMiddleware, 12 | ) 13 | 14 | FAIR_TEAM = [ 15 | {"name": "Leonardo Guerreiro Azevedo", "email": "lga@br.ibm.com"}, 16 | ] 17 | 18 | # TODO: Discover how to include more than one contact in the fast api contact info. 19 | app = FastAPI( 20 | title="2BFAIR-backend", 21 | version="0.0.1", 22 | contact={ 23 | "name": "Leonardo Guerreiro Azevedo", 24 | "url": "http://ibm.biz/leonardo", 25 | "email": "lga@br.ibm.com", 26 | }, 27 | ) 28 | 29 | 30 | origins = [ 31 | "http://localhost:4200", 32 | "http://localhost:42000", 33 | ] 34 | 35 | app.add_middleware( 36 | CORSMiddleware, 37 | allow_origins=["*"], 38 | allow_credentials=True, 39 | allow_methods=["*"], 40 | allow_headers=["*"], 41 | ) 42 | app.add_middleware(NotificationMiddleware) 43 | 44 | app.include_router(evaluation_router) 45 | app.include_router(configuration_router) 46 | app.include_router(check_app_router) 47 | -------------------------------------------------------------------------------- /tobefair-frontend/README.md: -------------------------------------------------------------------------------- 1 | # 2BFAIR-Frontend 2 | 3 | This is the frontend application for the 2BFAIR project, built with Angular. 4 | 5 | - To run the 2BFAIR-frontend, the 2BFAIR-backend should be run. You can start the backend locally or use the backend running on the cluster. 6 | You define the 2BFAIR-backend to be used by setting the environment variable `BACKEND_URL`, e.g., `export BACKEND _URL =http://localhost:8000`. 7 | - Note that if the variable is not set, the backend running locally will be considered. It is defined in `server.js` through: 8 | 9 | ```js 10 | app.get("/get-backend", (req, res) => { 11 | res.send(process.env.BACKEND_URL ?? "http://localhost:8000"); 12 | }); 13 | ``` 14 | 15 | - Check if the `BACKEND_URL` is pointing out to where the backend is running: `echo $BACKEND_URL`. 16 | - Install the dependencies: `npm install --legacy-peer-deps` 17 | - Build the application: `ng build` 18 | - Start the application: `npm run server` 19 | - Access the application at [http://localhost:42000](http://localhost:42000). 20 | 21 | ## To reflect code changes 22 | 23 | - After making changes to the code, run `ng build` to build the project. This command compiles the Angular application into static files in the /`dist` directory. 24 | - For active development, consider using `ng serve` instead of `npm run server`. The former command automatically reflects code changes without the need for a manual build. In this case, you access the application at [http://localhost:4200](http://localhost:4200). 25 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/explorer/explorer.component.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: "IBM Plex Sans", sans-serif; 3 | } 4 | 5 | :host div.outer { 6 | padding: 1em; 7 | } 8 | 9 | .outer { 10 | display: flex; 11 | align-items: center; 12 | } 13 | /*Explore styles*/ 14 | .explore { 15 | display: grid; 16 | grid-template-columns: 2fr 1fr; 17 | margin-bottom: -200px; 18 | } 19 | 20 | /*Graph styles*/ 21 | #graph ::ng-deep { 22 | width: 100%; 23 | height: 100%; 24 | margin: auto auto 50px auto; 25 | position: relative; 26 | } 27 | 28 | #graph ::ng-deep .hover-image { 29 | padding: 15px; 30 | } 31 | 32 | #graph ::ng-deep .axis { 33 | font-size: 42px; 34 | font-weight: 900; 35 | padding: 25px; 36 | color: #525252; 37 | shape-rendering: geometricPrecision; 38 | } 39 | 40 | #graph ::ng-deep .total-score { 41 | font-size: 42px; 42 | fill: #525252; 43 | shape-rendering: geometricPrecision; 44 | } 45 | 46 | /*Priority-suggestions styles*/ 47 | .priority-suggestions { 48 | margin: -20px 20px; 49 | } 50 | .priority-suggestions h3 { 51 | font-weight: normal; 52 | font-size: 20px; 53 | } 54 | 55 | .priority-suggestions a { 56 | color: black; 57 | text-decoration: none; 58 | } 59 | 60 | .priority-suggestions a:hover { 61 | color: #0f62fe; 62 | } 63 | 64 | .priority-suggestions ::ng-deep li { 65 | font-size: 15px; 66 | padding: 10px 0px; 67 | } 68 | 69 | .priority-suggestions ::ng-deep ul { 70 | list-style-image: url("../assets/li-icon.png"); 71 | } 72 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/notification.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@angular/core"; 2 | import { FAIRNotification } from "../models/FAIRnotification"; 3 | import { FairnessEvaluation } from "../models/fairness-evaluation"; 4 | import { BehaviorSubject } from "rxjs"; 5 | 6 | @Injectable({ 7 | providedIn: 'root', 8 | }) 9 | export class NotificationService { 10 | 11 | private notificationsSubject: BehaviorSubject = 12 | new BehaviorSubject([]); 13 | 14 | setNotifications( 15 | notifications: FAIRNotification[], 16 | ): void { 17 | let adaptedNotifications: FAIRNotification[] = []; 18 | 19 | for(let index = 0; index < notifications.length; index++){ 20 | adaptedNotifications.push({ 21 | // Giving an ID to the notification to make it easier to close the notification 22 | // the ID corresponds to the location of the notification in the notificationSubject array. 23 | id: index, 24 | type: notifications[index].type, 25 | title: notifications[index].title, 26 | description: notifications[index].description, 27 | isOpen: true 28 | }); 29 | }; 30 | 31 | this.notificationsSubject.next(adaptedNotifications); 32 | }; 33 | 34 | getNotifications(){ 35 | return this.notificationsSubject 36 | }; 37 | 38 | closeNotification(notificationID:number): void{ 39 | this.notificationsSubject.value[notificationID].isOpen = false; 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /tobefair_framework/model/results/test_specific_recommendation.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import List, cast 5 | 6 | from pydantic import BaseModel, ValidationError 7 | 8 | from tobefair_framework.model.identifier.fair_dimension_id import FAIRDimensionID 9 | from tobefair_framework.model.identifier.fairness_test_id import FAIRnessTestID 10 | from tobefair_framework.model.recommendation import Recommendation 11 | 12 | 13 | class TestSpecificRecommendation(BaseModel): 14 | recommendation: Recommendation 15 | test_id: FAIRnessTestID 16 | dimension_id: FAIRDimensionID 17 | 18 | def __init__(self, **data): 19 | try: 20 | test_id = cast(FAIRnessTestID, data["test_id"]) 21 | data["dimension_id"] = ( 22 | test_id.get_parent_id().get_parent_id().get_parent_id() 23 | ) 24 | super().__init__(**data) 25 | except Exception: 26 | raise ValidationError 27 | 28 | @classmethod 29 | def get_priority_test_specific_recommendations( 30 | cls, 31 | test_specific_recommendations: List["TestSpecificRecommendation"], 32 | number_of_recommendations: int, 33 | ) -> List["TestSpecificRecommendation"]: 34 | test_specific_recommendations.sort() 35 | return test_specific_recommendations[:number_of_recommendations] 36 | 37 | def __lt__(self, other: "TestSpecificRecommendation") -> bool: 38 | return self.recommendation.priority < other.recommendation.priority 39 | -------------------------------------------------------------------------------- /tobefair_backend/repository/file_format_repository.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import List 5 | 6 | from tobefair_backend.constants import FILE_FORMAT_PATH 7 | from tobefair_backend.model.file_format import FileFormat 8 | from tobefair_backend.repository.json_dictionary_repository import ( 9 | JsonDictionaryRepository, 10 | ) 11 | 12 | 13 | class FileFormatRepository(JsonDictionaryRepository[FileFormat]): 14 | @classmethod 15 | def file_path(cls) -> str: 16 | return FILE_FORMAT_PATH 17 | 18 | @classmethod 19 | def dictionary_to_model(cls, dictionary: dict, **kwargs) -> FileFormat | None: 20 | try: 21 | return FileFormat.model_validate(dictionary) 22 | except Exception: 23 | return None 24 | 25 | @classmethod 26 | def science_file_formats(cls) -> List[FileFormat]: 27 | return [ 28 | file_format 29 | for file_format in cls.all() 30 | if "scientific format" in file_format.reason 31 | ] 32 | 33 | @classmethod 34 | def long_term_file_formats(cls) -> List[FileFormat]: 35 | return [ 36 | file_format 37 | for file_format in cls.all() 38 | if "long term format" in file_format.reason 39 | ] 40 | 41 | @classmethod 42 | def open_file_formats(cls) -> List[FileFormat]: 43 | return [ 44 | file_format 45 | for file_format in cls.all() 46 | if "open format" in file_format.reason 47 | ] 48 | -------------------------------------------------------------------------------- /tobefair-frontend/projects/to-be-fair/src/lib/evaluate/evaluate.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { 3 | Router, 4 | RouterOutlet, 5 | RouterLink, 6 | RouterLinkActive, 7 | } from '@angular/router'; 8 | import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; 9 | import { EvaluationService } from '@dwb/to-be-fair'; 10 | 11 | import { ButtonModule } from 'carbon-components-angular'; 12 | 13 | @Component({ 14 | selector: 'app-evaluate', 15 | standalone: true, 16 | imports: [ 17 | RouterOutlet, 18 | RouterLink, 19 | RouterLinkActive, 20 | ReactiveFormsModule, 21 | ButtonModule, 22 | ], 23 | templateUrl: './evaluate.component.html', 24 | styleUrl: './evaluate.component.css', 25 | }) 26 | export class EvaluateComponent { 27 | public evaluationRequestForm = new FormGroup({ 28 | digitalObjectURI: new FormControl(''), 29 | community: new FormControl(''), 30 | task: new FormControl(''), 31 | }); 32 | 33 | evaluationService: EvaluationService = inject(EvaluationService); 34 | error: string | null | undefined; 35 | 36 | constructor(private router: Router) {} 37 | 38 | submitEvaluationRequest() { 39 | const { digitalObjectURI, community, task } = 40 | this.evaluationRequestForm.value; 41 | this.evaluationService.requestStandalone( 42 | digitalObjectURI ?? '', 43 | community ?? '', 44 | task ?? '', 45 | ); 46 | this.evaluationService.error$.subscribe((error) => { 47 | this.error = error; 48 | }); 49 | this.router.navigate(['/result']); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tobefair_framework/core/notification/notification_context.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import threading 5 | from typing import Literal 6 | 7 | from pydantic import BaseModel 8 | 9 | from tobefair_framework.core.notification.contexts import request_id_var 10 | 11 | 12 | class Notification(BaseModel): 13 | type: Literal["error", "success", "warning", "information"] 14 | title: str 15 | description: str 16 | 17 | 18 | registry_lock = threading.Lock() 19 | 20 | 21 | class NotificationRegistry: 22 | 23 | notification_registry: dict[str, list[Notification]] = {} 24 | 25 | @classmethod 26 | def add_notification(cls, notification: Notification) -> None: 27 | request_id = request_id_var.get() 28 | with registry_lock: 29 | if request_id not in cls.notification_registry.keys(): 30 | cls.notification_registry[request_id] = [] 31 | cls.notification_registry[request_id].append(notification) 32 | 33 | @classmethod 34 | def get_notifications(cls) -> list[Notification]: 35 | request_id = request_id_var.get() 36 | with registry_lock: 37 | if request_id not in cls.notification_registry.keys(): 38 | return [] 39 | return cls.notification_registry[request_id] 40 | 41 | @classmethod 42 | def clear_notifications(cls) -> None: 43 | request_id = request_id_var.get() 44 | with registry_lock: 45 | if request_id in cls.notification_registry.keys(): 46 | del cls.notification_registry[request_id_var.get()] 47 | -------------------------------------------------------------------------------- /tobefair_backend/model/resources/data_record.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import List 5 | 6 | from pydantic import BaseModel, Field 7 | 8 | from tobefair_backend.model.resources.data_size import DataSize, DataType 9 | from tobefair_backend.model.resources.typed_link import TypedLink 10 | 11 | 12 | class DataRecord(BaseModel): 13 | link: TypedLink | None = None 14 | content_size: DataSize | None = None 15 | header_content_size: DataSize | None = None 16 | tika_content_types: List[DataType] = [] 17 | header_content_type: DataType | None = None 18 | measured_variables: List[str] | None = None 19 | schema_: str | None = Field( 20 | default=None, 21 | alias="schema", 22 | ) 23 | tika_data_content: str | None = None 24 | 25 | @property 26 | def claimed_size(self) -> DataSize | None: 27 | return link.content_size if (link := self.link) else None 28 | 29 | @property 30 | def claimed_type(self) -> DataType | None: 31 | return link.type if (link := self.link) else None 32 | 33 | @property 34 | def truncated(self) -> bool: 35 | return ( 36 | self.header_content_size is not None 37 | and self.content_size is not None 38 | and self.content_size < self.header_content_size 39 | ) 40 | 41 | @property 42 | def data_types(self) -> List[DataType]: 43 | return (self.tika_content_types) + ( 44 | [header_content_type] 45 | if (header_content_type := self.header_content_type) 46 | else [] 47 | ) 48 | -------------------------------------------------------------------------------- /docs/_templates/module.rst: -------------------------------------------------------------------------------- 1 | {# The :autogenerated: tag is picked up by breadcrumbs.html to suppress "Edit on Github" link #} 2 | :autogenerated: 3 | 4 | {{ fullname }} module 5 | {% for item in range(7 + fullname|length) -%}={%- endfor %} 6 | 7 | .. currentmodule:: {{ fullname }} 8 | 9 | .. automodule:: {{ fullname }} 10 | {% if members -%} 11 | :members: {{ members|join(", ") }} 12 | :undoc-members: 13 | :show-inheritance: 14 | :member-order: bysource 15 | 16 | Summary 17 | ------- 18 | 19 | {%- if exceptions %} 20 | 21 | Exceptions: 22 | 23 | .. autosummary:: 24 | :nosignatures: 25 | {% for item in exceptions %} 26 | {{ item }} 27 | {%- endfor %} 28 | {%- endif %} 29 | 30 | {%- if classes %} 31 | 32 | Classes: 33 | 34 | .. autosummary:: 35 | :nosignatures: 36 | {% for item in classes %} 37 | {{ item }} 38 | {%- endfor %} 39 | {%- endif %} 40 | 41 | {%- if functions %} 42 | 43 | Functions: 44 | 45 | .. autosummary:: 46 | :nosignatures: 47 | {% for item in functions %} 48 | {{ item }} 49 | {%- endfor %} 50 | {%- endif %} 51 | {%- endif %} 52 | 53 | {% set data = get_members(typ='data', in_list='__all__') %} 54 | {%- if data %} 55 | 56 | Data: 57 | 58 | .. autosummary:: 59 | :nosignatures: 60 | {% for item in data %} 61 | {{ item }} 62 | {%- endfor %} 63 | {%- endif %} 64 | 65 | {% set all_refs = get_members(in_list='__all__', include_imported=True, out_format='refs') %} 66 | {% if all_refs %} 67 | ``__all__``: {{ all_refs|join(", ") }} 68 | {%- endif %} 69 | 70 | 71 | {% if members %} 72 | Reference 73 | --------- 74 | 75 | {%- endif %} 76 | -------------------------------------------------------------------------------- /tobefair_framework/model/configuration/fair_dimension_configuration.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import Dict, List 5 | 6 | from pydantic import BaseModel 7 | 8 | from tobefair_framework.model.composite.identifiable_composite import ( 9 | IdentifiableComposite, 10 | ) 11 | from tobefair_framework.model.configuration.fair_principle_configuration import ( 12 | FAIRPrincipleConfiguration, 13 | ) 14 | from tobefair_framework.model.identifier.fair_dimension_id import ( 15 | FAIRDimensionID, 16 | FAIRDimensionIDs, 17 | ) 18 | from tobefair_framework.model.identifier.fair_principle_id import FAIRPrincipleID 19 | 20 | 21 | class FAIRDimensionConfiguration( 22 | BaseModel, IdentifiableComposite[FAIRPrincipleConfiguration] 23 | ): 24 | id: FAIRDimensionID 25 | name: str 26 | principles: Dict[FAIRPrincipleID, FAIRPrincipleConfiguration] 27 | 28 | @property 29 | def get_id(self) -> FAIRDimensionID: 30 | return self.id 31 | 32 | @classmethod 33 | def get_dimension_name_from_id(cls, id: FAIRDimensionID) -> str: 34 | match id: 35 | case FAIRDimensionIDs.F.value: 36 | return "Findability" 37 | case FAIRDimensionIDs.A.value: 38 | return "Accessibility" 39 | case FAIRDimensionIDs.I.value: 40 | return "Interoperability" 41 | case FAIRDimensionIDs.R.value: 42 | return "Reusability" 43 | case _: 44 | raise Exception("Dimension ID not recognized") 45 | 46 | def get_children(self) -> List[FAIRPrincipleConfiguration]: 47 | return list(self.principles.values()) 48 | -------------------------------------------------------------------------------- /tobefair_backend/utils/dict_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from collections import defaultdict 5 | from typing import Any, Callable, Dict, List, TypeVar 6 | 7 | 8 | def access_multilevel_implicit_dict(d=Dict[Any, Any], **kwargs): 9 | """ 10 | Retrieves value from a specific layer of an implicit nested dictionary. 11 | Use dict_name to pass the method that allows access of the dictionary 12 | at the n-th level. Use key to pass the key that should be used 13 | at the n-th level. An implicit dictionary is a dictionary in which 14 | values are of a type that contains at least one field which is a dictionary. 15 | """ 16 | curr_dict = d 17 | i = 1 18 | while i <= len(kwargs.keys()) / 2: 19 | curr_obj = curr_dict[kwargs[f"key{i}"]] 20 | curr_dict = vars(curr_obj)[kwargs[f"dict_name{i}"]] 21 | i += 1 22 | return curr_dict 23 | 24 | 25 | def remove_empty_list_values(dict: Dict[Any, Any]) -> Dict[Any, Any]: 26 | no_empty_list_value_dict: Dict[Any, Any] = {} 27 | for key in dict: 28 | if dict[key] and len(dict[key]) > 0: 29 | no_empty_list_value_dict[key] = dict[key] 30 | return no_empty_list_value_dict 31 | 32 | 33 | def remove_empty_fields(dict: Dict) -> Dict: 34 | return {k: v for k, v in dict.items() if v} 35 | 36 | 37 | Object = TypeVar("Object") 38 | Property = TypeVar("Property") 39 | 40 | 41 | def group( 42 | objects: List[Object], property: Callable[[Object], Property] 43 | ) -> Dict[Property, List[Object]]: 44 | d: Dict[Property, List[Object]] = defaultdict(List) 45 | for object in objects: 46 | d[property(object)] += [object] 47 | return d 48 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 56 | 57 | -------------------------------------------------------------------------------- /tobefair_framework/model/identifier/identifier_info.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import re 5 | import uuid 6 | from typing import List 7 | 8 | from pydantic import BaseModel 9 | 10 | from tobefair_framework.model.identifier.identifier_type import IdentifierType 11 | 12 | 13 | class IdentifierInfo(BaseModel): 14 | identifier: str 15 | identifier_schemas: List[str] = [] 16 | preferred_schema: str | None = None 17 | url: str | None = None 18 | 19 | def get_identifier_type(self) -> IdentifierType: 20 | if self.url: 21 | return IdentifierType.GUID 22 | if self.is_hash(identifier=self.identifier): 23 | return IdentifierType.HASH 24 | elif self.is_uuid(identifier=self.identifier): 25 | return IdentifierType.UUID 26 | return IdentifierType.NOT_IDENTIFIED 27 | 28 | @classmethod 29 | def is_uuid(cls, identifier: str) -> bool: 30 | try: 31 | uuid_version = uuid.UUID(identifier).version 32 | if uuid_version is not None: 33 | return True 34 | else: 35 | return False 36 | except ValueError: 37 | return False 38 | 39 | @classmethod 40 | def is_hash(cls, identifier: str) -> bool: 41 | import hashid 42 | 43 | try: 44 | hash = hashid.HashID() 45 | valid_hash = False 46 | for hash_type in hash.identifyHash(identifier): 47 | if re.search(r"^(sha|md5|blake)", hash_type.name, re.IGNORECASE): 48 | valid_hash = True 49 | return valid_hash 50 | except Exception: 51 | return False 52 | 53 | 54 | mocked_identifier_info = IdentifierInfo(identifier="") 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | docs/api/* 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | ENV/ 92 | env.bak/ 93 | venv.bak/ 94 | 95 | # Spyder project settings 96 | .spyderproject 97 | .spyproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # mkdocs documentation 103 | /site 104 | 105 | # mypy 106 | .mypy_cache/ 107 | 108 | # VS Code 109 | .vscode/ 110 | -------------------------------------------------------------------------------- /tobefair_backend/service/routes/evaluation_routes.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from fastapi import APIRouter 5 | 6 | from tobefair_backend.collector.digital_object_collector_from_url import ( 7 | DigitalObjectCollectorFromURL, 8 | ) 9 | from tobefair_backend.collector.metadata_collector_schemaorg_jsonld import ( 10 | MetadataCollectorSchemaOrgJsonLD, 11 | ) 12 | from tobefair_backend.constants import ( 13 | EVALUATORS_PACKAGE, 14 | FAIRNESS_CONFIGURATION_FILE_PATH, 15 | ) 16 | from tobefair_framework.controller.evaluation_controller import EvaluationController 17 | from tobefair_framework.core.configuration.fairness_configuration_file_dao import ( 18 | FAIRnessConfigurationFileDAO, 19 | ) 20 | from tobefair_framework.model.fairness_evaluation_request import ( 21 | FAIRnessEvaluationRequest, 22 | ) 23 | from tobefair_framework.model.results.fairness_result import FAIRnessEvaluationResponse 24 | 25 | evaluation_router = APIRouter() 26 | 27 | TAG_FAIRNESS_EVALUATION = "2BFAIR" 28 | 29 | 30 | @evaluation_router.post("/evaluate", tags=[TAG_FAIRNESS_EVALUATION]) 31 | def evaluate( 32 | evaluation_request: FAIRnessEvaluationRequest, 33 | ) -> FAIRnessEvaluationResponse: 34 | fairness_configuration_dao = FAIRnessConfigurationFileDAO( 35 | file_path=FAIRNESS_CONFIGURATION_FILE_PATH 36 | ) 37 | fairness_configuration = fairness_configuration_dao.read_configuration() 38 | evaluation_controller = EvaluationController( 39 | digital_object_collector=DigitalObjectCollectorFromURL(), 40 | metadata_collector=MetadataCollectorSchemaOrgJsonLD(), 41 | fairness_configuration=fairness_configuration, 42 | ) 43 | result = evaluation_controller.evaluate( 44 | evaluation_request=evaluation_request, evaluators_package=EVALUATORS_PACKAGE 45 | ) 46 | return result 47 | -------------------------------------------------------------------------------- /tobefair_backend/collector/digital_object_collector_from_url.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from tobefair_backend.utils.request_helper import RequestHelper 5 | from tobefair_framework.core.collector.digital_object_collector import ( 6 | DigitalObjectCollector, 7 | ) 8 | from tobefair_framework.core.collector.metadata_collector import MetadataCollector 9 | from tobefair_framework.model.accept_type import AcceptType 10 | from tobefair_framework.model.digital_object_info import DigitalObjectInfo 11 | from tobefair_framework.model.identifier.identifier_info import IdentifierInfo 12 | from tobefair_framework.model.landing_page import LandingPage 13 | from tobefair_framework.model.metadata.metadata_record import MetadataRecord 14 | 15 | 16 | class DigitalObjectCollectorFromURL(DigitalObjectCollector): 17 | 18 | def _read_digital_object_info( 19 | self, 20 | identifier_info: IdentifierInfo, 21 | metadata_collector: MetadataCollector, 22 | ) -> DigitalObjectInfo: 23 | metadata_record: MetadataRecord | None = None 24 | landing_page = None 25 | if identifier_info.url: 26 | if negotiation_result := RequestHelper().negotiate_content( 27 | identifier_info.url, [AcceptType(mime_types=["text/html"])] 28 | ): 29 | landing_page = LandingPage( 30 | decoded_html_body=negotiation_result.response, 31 | url=identifier_info.url, 32 | ) 33 | metadata_record = metadata_collector.get_metadata_record( 34 | raw_digital_object=negotiation_result.response 35 | ) 36 | return DigitalObjectInfo( 37 | identifier_info=identifier_info, 38 | metadata_record=metadata_record, 39 | landing_page=landing_page, 40 | ) 41 | -------------------------------------------------------------------------------- /tobefair_framework/model/metadata/metadata_standard.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | from typing import Iterable, List 6 | 7 | from pydantic import BaseModel 8 | 9 | 10 | class MetadataStandard(BaseModel): 11 | 12 | name: str 13 | subjects: List[str] = [] 14 | external_ids: List["ExternalID"] = [] 15 | type: "MetadataStandardType | None" = None 16 | 17 | @classmethod 18 | def get_type_from_subjects(cls, subjects: List[str]) -> "MetadataStandardType": 19 | if subjects == ["sciences"] or all( 20 | subject == "Multidisciplinary" for subject in subjects 21 | ): 22 | return MetadataStandardType.Generic 23 | else: 24 | return MetadataStandardType.Disciplinary 25 | 26 | def __eq__(self, value: object) -> bool: 27 | try: 28 | value_name = getattr(value, "name", None) 29 | value_external_ids: List["ExternalID"] = getattr(value, "external_ids", []) 30 | return self.name == value_name or any( 31 | map( 32 | lambda external_id: external_id in value_external_ids, 33 | self.external_ids, 34 | ) 35 | ) 36 | except Exception: 37 | return False 38 | 39 | def external_id_uris(self) -> Iterable[str]: 40 | return map(lambda external_id: external_id.value, self.external_ids) 41 | 42 | 43 | class ExternalID(BaseModel): 44 | value: str 45 | 46 | def __eq__(self, value: object) -> bool: 47 | if isinstance(value, ExternalID): 48 | return self.value == value.value 49 | return False 50 | 51 | 52 | class MetadataStandardType(Enum): 53 | Generic = "Generic" 54 | Disciplinary = "Disciplinary" 55 | 56 | 57 | class MetadataStandardSubject(BaseModel): 58 | value: str 59 | -------------------------------------------------------------------------------- /tests/evaluators/reusability/test_R1_1_evaluator.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from tests.evaluators.fairness_principle_evaluation_tester import ( 5 | FAIRNESS_CONFIGURATION_FOR_TESTS, 6 | FAIRnessPrincipleEvaluationTester, 7 | ) 8 | from tobefair_backend.principle_evaluators.accessible_usage_license_evaluator import ( 9 | AccessibleUsageLicenseMetadataEvaluator, 10 | ) 11 | from tobefair_framework.model.metadata.metadata_record import MetadataRecord 12 | 13 | 14 | class TestR11LicenseEvaluator(FAIRnessPrincipleEvaluationTester): 15 | def setUp(self): 16 | self.evaluator = AccessibleUsageLicenseMetadataEvaluator( 17 | fairness_configuration=FAIRNESS_CONFIGURATION_FOR_TESTS 18 | ) 19 | 20 | def test_r1_1_01m_1_passes(self): 21 | test_result = ( 22 | self.evaluator._evaluate_usage_license_information_available_r1_1_01m_1( 23 | metadata_record=MetadataRecord( 24 | is_machine_retrieved=False, 25 | raw_value={"license": "License Information"}, 26 | ) 27 | ) 28 | ) 29 | self.assert_test_passed(test_result) 30 | 31 | def test_r1_1_01m_1_fails(self): 32 | test_result = ( 33 | self.evaluator._evaluate_usage_license_information_available_r1_1_01m_1( 34 | metadata_record=MetadataRecord( 35 | is_machine_retrieved=False, raw_value={"license": ""} 36 | ) 37 | ) 38 | ) 39 | self.assert_test_failed(test_result) 40 | 41 | test_result = ( 42 | self.evaluator._evaluate_usage_license_information_available_r1_1_01m_1( 43 | metadata_record=MetadataRecord(is_machine_retrieved=False, raw_value={}) 44 | ) 45 | ) 46 | self.assert_test_failed(test_result) 47 | -------------------------------------------------------------------------------- /tobefair_framework/tool_example/main_example.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from tobefair_framework.controller.evaluation_controller import EvaluationController 5 | from tobefair_framework.core.configuration.fairness_configuration_file_dao import ( 6 | FAIRnessConfigurationFileDAO, 7 | ) 8 | from tobefair_framework.framework_constants import ( 9 | FAIRNESS_CONFIGURATION_FILE_PATH_FOR_THE_FRAMEWORK, 10 | ) 11 | from tobefair_framework.model.fairness_evaluation_request import ( 12 | FAIRnessEvaluationRequest, 13 | ) 14 | from tobefair_framework.tool_example.digital_object_collector_from_file import ( 15 | DigitalObjectCollectorFromFile, 16 | ) 17 | from tobefair_framework.tool_example.metadata_collector_schema_org_json_ld_simple import ( # noqa E501 18 | MetadataCollectorSchemaorgJsonldSimple, 19 | ) 20 | 21 | EVALUATORS_PACKAGE: str = "tobefair_framework.tool_example.principle_evaluators" 22 | evaluation_request: FAIRnessEvaluationRequest = FAIRnessEvaluationRequest( 23 | resource_id="https://zenodo.org/records/8255910" 24 | ) 25 | 26 | file_path: str = "tobefair_framework/tool_example/digital_object_example.json" 27 | 28 | digital_object_collector = DigitalObjectCollectorFromFile(file_path=file_path) 29 | 30 | 31 | fairness_configuration_dao = FAIRnessConfigurationFileDAO( 32 | file_path=FAIRNESS_CONFIGURATION_FILE_PATH_FOR_THE_FRAMEWORK 33 | ) 34 | fairness_configuration = fairness_configuration_dao.read_configuration() 35 | 36 | evaluation_controller = EvaluationController( 37 | digital_object_collector=digital_object_collector, 38 | metadata_collector=MetadataCollectorSchemaorgJsonldSimple(), 39 | fairness_configuration=fairness_configuration, 40 | ) 41 | 42 | result = evaluation_controller.evaluate( 43 | evaluation_request=evaluation_request, 44 | evaluators_package=EVALUATORS_PACKAGE, 45 | ) 46 | print(result) 47 | -------------------------------------------------------------------------------- /tests/utils/manage_fairness_response.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | 6 | from tobefair_backend.collector.digital_object_collector_from_url import ( 7 | DigitalObjectCollectorFromURL, 8 | ) 9 | from tobefair_backend.collector.metadata_collector_schemaorg_jsonld import ( 10 | MetadataCollectorSchemaOrgJsonLD, 11 | ) 12 | from tobefair_backend.constants import ( 13 | EVALUATORS_PACKAGE, 14 | FAIRNESS_CONFIGURATION_FILE_PATH, 15 | ) 16 | from tobefair_framework.controller.evaluation_controller import EvaluationController 17 | from tobefair_framework.core.configuration.fairness_configuration_file_dao import ( 18 | FAIRnessConfigurationFileDAO, 19 | ) 20 | from tobefair_framework.model.fairness_evaluation_request import ( 21 | FAIRnessEvaluationRequest, 22 | ) 23 | from tobefair_framework.model.results.fairness_result import FAIRnessEvaluationResponse 24 | 25 | 26 | def save_fairness_evaluation_response_to_file(resource_id: str, file_path: str): 27 | evaluation_request = FAIRnessEvaluationRequest(resource_id=resource_id) 28 | fairness_configuration_dao = FAIRnessConfigurationFileDAO( 29 | file_path=FAIRNESS_CONFIGURATION_FILE_PATH 30 | ) 31 | fairness_configuration = fairness_configuration_dao.read_configuration() 32 | evaluation_controller = EvaluationController( 33 | digital_object_collector=DigitalObjectCollectorFromURL(), 34 | metadata_collector=MetadataCollectorSchemaOrgJsonLD(), 35 | fairness_configuration=fairness_configuration, 36 | ) 37 | evaluation_result: FAIRnessEvaluationResponse = evaluation_controller.evaluate( 38 | evaluation_request=evaluation_request, evaluators_package=EVALUATORS_PACKAGE 39 | ) 40 | with open(file_path, "w") as file: 41 | response_as_dict = evaluation_result.model_dump(mode="json") 42 | json.dump(response_as_dict, file, indent=4) 43 | -------------------------------------------------------------------------------- /tobefair_framework/module.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | """Module functions.""" 5 | 6 | __copyright__ = """ 7 | LICENSED INTERNAL CODE. PROPERTY OF IBM. 8 | IBM Research Licensed Internal Code 9 | (C) Copyright IBM Corp. 2025 10 | ALL RIGHTS RESERVED 11 | """ 12 | 13 | from dataclasses import dataclass 14 | from typing import Callable 15 | 16 | 17 | def hello_world() -> str: 18 | """Return Hello World.""" 19 | return "Hello World" 20 | 21 | 22 | class Foo: 23 | """An example class.""" 24 | 25 | def __init__(self, a: int) -> None: 26 | """Initialize Foo. 27 | 28 | Args: 29 | a : documentation for argument a. 30 | """ 31 | self.a = a 32 | 33 | def method_that_would_really_waste_your_time_if_it_fails(self) -> str: 34 | """Static typing could help you fix a bug in here before running any test. 35 | 36 | Returns: 37 | documentation for the returned string 38 | """ 39 | self.a_times_1 = [1] * self.a 40 | # example that would trigger a mypy typechecking failure 41 | # return self.a + "When will you find out that this fails?" 42 | return f"{self.a} This works" 43 | 44 | 45 | @dataclass 46 | class Bar: 47 | """An example dataclass.""" 48 | 49 | #: some documentation for attribute b 50 | b: str 51 | 52 | def set_b(self, compute_b: Callable[[], str]) -> None: 53 | """Set b from return of a given function. 54 | 55 | Args: 56 | compute_b (Callable[[], str]): function without arguments to determine b. 57 | """ 58 | self.b = compute_b() 59 | 60 | 61 | if __name__ == "__main__": 62 | # foo = Foo(1.0) # example that would fail (but mypy can tell you in advance) 63 | foo = Foo(1) 64 | 65 | bar = Bar(b="excellent to each other") 66 | print(bar.b) 67 | 68 | bar.set_b(hello_world) 69 | print(bar.b) 70 | -------------------------------------------------------------------------------- /tobefair_framework/model/fairness_evaluation_maturity.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | from typing import Any, List 6 | 7 | from pydantic import BaseModel, ValidationInfo, model_validator 8 | from pydantic.functional_validators import ModelWrapValidatorHandler 9 | 10 | 11 | class FAIRnessMaturity(BaseModel): 12 | value: str 13 | 14 | @model_validator(mode="wrap") 15 | @classmethod 16 | def validator( 17 | cls, values: Any, handler: ModelWrapValidatorHandler, info: ValidationInfo 18 | ) -> "FAIRnessMaturity": 19 | if isinstance(values, str): 20 | return cls(value=values) 21 | return handler(values) 22 | 23 | def __lt__(self, other: "FAIRnessMaturity") -> bool: 24 | return FAIRnessMaturities.all().index(self) < FAIRnessMaturities.all().index( 25 | other 26 | ) 27 | 28 | 29 | class FAIRnessMaturities(Enum): 30 | Incomplete = FAIRnessMaturity(value="Incomplete") 31 | Initial = FAIRnessMaturity(value="Initial") 32 | Moderate = FAIRnessMaturity(value="Moderate") 33 | Advanced = FAIRnessMaturity(value="Advanced") 34 | 35 | @classmethod 36 | def all(cls) -> List[FAIRnessMaturity]: 37 | return [maturity.value for maturity in FAIRnessMaturities] 38 | 39 | 40 | def get_highest_maturity(maturity_a, maturity_b): 41 | if maturity_a == FAIRnessMaturities.Incomplete.value: 42 | return maturity_b 43 | if maturity_b == FAIRnessMaturities.Incomplete.value: 44 | return maturity_a 45 | if maturity_a == FAIRnessMaturities.Initial.value: 46 | return maturity_b 47 | if maturity_b == FAIRnessMaturities.Initial.value: 48 | return maturity_a 49 | if maturity_a == FAIRnessMaturities.Moderate.value: 50 | return maturity_b 51 | if maturity_b == FAIRnessMaturities.Moderate.value: 52 | return maturity_a 53 | return maturity_a 54 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Welcome

5 |

6 | 2BFAIR is a tool that uses FAIR principles to enhance your data and improve scientific discovery in a fully customizable way. 7 |

8 |
9 | 10 |
16 | 17 | 24 | 25 |
26 | 27 | See an evaluation example: 28 | 31 | 32 | 33 | 36 |
37 | 38 |
39 | 40 |
41 | 42 |
43 |

Additional Resources

44 |
45 | 46 | 47 | 48 | 49 |
50 |
51 | 52 |
53 | 54 |
55 |
56 | -------------------------------------------------------------------------------- /tests/service/test_result_order.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import unittest 5 | 6 | from tobefair_backend.collector.digital_object_collector_from_url import ( 7 | DigitalObjectCollectorFromURL, 8 | ) 9 | from tobefair_backend.collector.metadata_collector_schemaorg_jsonld import ( 10 | MetadataCollectorSchemaOrgJsonLD, 11 | ) 12 | from tobefair_backend.constants import ( 13 | EVALUATORS_PACKAGE, 14 | FAIRNESS_CONFIGURATION_FILE_PATH, 15 | ) 16 | from tobefair_framework.controller.evaluation_controller import EvaluationController 17 | from tobefair_framework.core.configuration.fairness_configuration_file_dao import ( 18 | FAIRnessConfigurationFileDAO, 19 | ) 20 | from tobefair_framework.model.fairness_evaluation_request import ( 21 | FAIRnessEvaluationRequest, 22 | ) 23 | 24 | 25 | class TestResultOrder(unittest.TestCase): 26 | 27 | def setUp(self) -> None: 28 | fairness_configuration_dao = FAIRnessConfigurationFileDAO( 29 | file_path=FAIRNESS_CONFIGURATION_FILE_PATH 30 | ) 31 | fairness_configuration = fairness_configuration_dao.read_configuration() 32 | self.evaluation_controller = EvaluationController( 33 | digital_object_collector=DigitalObjectCollectorFromURL(), 34 | metadata_collector=MetadataCollectorSchemaOrgJsonLD(), 35 | fairness_configuration=fairness_configuration, 36 | ) 37 | 38 | def test_correct_order(self): 39 | result = self.evaluation_controller.evaluate( 40 | evaluation_request=FAIRnessEvaluationRequest(resource_id="0000"), 41 | evaluators_package=EVALUATORS_PACKAGE, 42 | ) 43 | keys = list(result.detailed_results.dimension_results.keys()) 44 | self.assertEqual(keys[0].raw_value, "F") 45 | self.assertEqual(keys[1].raw_value, "A") 46 | self.assertEqual(keys[2].raw_value, "I") 47 | self.assertEqual(keys[3].raw_value, "R") 48 | -------------------------------------------------------------------------------- /tobefair_framework/model/identifier/fair_dimension_id.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | from typing import Any, List 6 | 7 | from pydantic import ( 8 | BaseModel, 9 | ValidationError, 10 | ValidationInfo, 11 | model_serializer, 12 | model_validator, 13 | ) 14 | from pydantic.functional_validators import ModelWrapValidatorHandler 15 | 16 | from tobefair_framework.model.identifier.id import ID 17 | 18 | 19 | class FAIRDimensionID(BaseModel, ID[str]): 20 | dimension_id: str 21 | 22 | def __lt__(self, other) -> bool: 23 | fair_dimension_id_raw_values: List[str] = ["F", "A", "I", "R"] 24 | if isinstance(other, FAIRDimensionID): 25 | try: 26 | self_index = fair_dimension_id_raw_values.index(self.raw_value) 27 | other_index = fair_dimension_id_raw_values.index(other.raw_value) 28 | return self_index < other_index 29 | except ValueError: 30 | return False 31 | return False 32 | 33 | @property 34 | def raw_value(self) -> str: 35 | return self.dimension_id 36 | 37 | def __hash__(self) -> int: 38 | return hash(self.raw_value) 39 | 40 | @model_validator(mode="wrap") 41 | @classmethod 42 | def validator( 43 | cls, values: Any, handler: ModelWrapValidatorHandler, info: ValidationInfo 44 | ): 45 | try: 46 | return handler(values) 47 | except ValidationError: 48 | if isinstance(values, str): 49 | return cls(dimension_id=values) 50 | return handler(values) 51 | 52 | @model_serializer 53 | def ser_model(self) -> str: 54 | return self.raw_value 55 | 56 | 57 | class FAIRDimensionIDs(Enum): 58 | F = FAIRDimensionID(dimension_id="F") 59 | A = FAIRDimensionID(dimension_id="A") 60 | I = FAIRDimensionID(dimension_id="I") 61 | R = FAIRDimensionID(dimension_id="R") 62 | -------------------------------------------------------------------------------- /tobefair_framework/tool_example/readme.md: -------------------------------------------------------------------------------- 1 | # Steps to implement a FAIRness evaluation tool 2 | 3 | - Create a package for the FAIRness evaluation tool, e.g., the package [tool_example](../tool_example/). 4 | - Create a module for the digital object collector implementation 5 | - E.g.: Implementation of `DigitalObjectCollectorFromFile` in the module [digital_object_collector_from_file.py](digital_object_collector_from_file.py), inheriting from `DigitalObjectCollector`, and implementing the method `_read_digital_object_info()`. 6 | - Create a module for the class responsible to parser the digital object content to a metadata representation 7 | - E.g.: Implementation of the class `MetadataCollectorSchemaorgJsonldSimple` in the module [metadata_collector_schema_org_json_ld_simple.py](./metadata_collector_schema_org_json_ld_simple.py), inheriting from `MetadataCollector`, and implementing the method `get_metadata_record()`. 8 | - In our simple example, the digital object is stored in file already in json-ld representation. 9 | - Create a script for the code to invoke the evaluators (e.g., [main_example.py](./main_example.py)) that runs the FAIRness evaluation. 10 | - Create an example of digital object to be handled by your tool, e.g., the json-ld file [digital_object_example.json](./digital_object_example.json). 11 | - Create a package for the evaluators, e.g., [principle_evaluators](./principle_evaluators/), and implement classes for each FAIRness metric and test. 12 | - In our example we implemented the `UniqueIdentifierEvaluator` present in the module [unique_identifier_evaluator.py](./principle_evaluators/unique_identifier_evaluator.py) with two tests to: 13 | - Check if the identifier is a hash or a UUID. 14 | - Check if the identifier is a GUID. 15 | - We decorate the class with `@evaluator_of_principle(FAIRPrincipleIDs.F1.value)` since it is responsible to evaluate FAIRness considering the principle `F1`. The decorator register this class as an evaluator to be used in the FAIRness assessment. -------------------------------------------------------------------------------- /tobefair_backend/model/resources/data_size.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import re 5 | from enum import Enum 6 | 7 | from pydantic import BaseModel 8 | 9 | 10 | class DataType(BaseModel): 11 | value: str 12 | 13 | 14 | class DataUnit(BaseModel): 15 | name: str 16 | 17 | 18 | class DataUnits(Enum): 19 | byte = DataUnit(name="byte") 20 | 21 | 22 | class DataSize(BaseModel): 23 | value: int 24 | unit: DataUnit = DataUnits.byte.value 25 | 26 | def __eq__(self, value: object) -> bool: 27 | if isinstance(value, DataSize): 28 | return self.value == value.value 29 | elif isinstance(value, int) or isinstance(value, float): 30 | return self.value == value 31 | return NotImplemented 32 | 33 | def __lt__(self, value: object) -> bool: 34 | if isinstance(value, DataSize): 35 | return self.value < value.value 36 | elif isinstance(value, int) or isinstance(value, float): 37 | return self.value < value 38 | return NotImplemented 39 | 40 | @classmethod 41 | def from_string(cls, size) -> "DataSize": 42 | try: 43 | bytematch = re.search( 44 | r"([0-9]+(?:[\.,][0-9]+)*)\s*([kMGTP]?(?:[Bb](?:ytes?)?))?", str(size) 45 | ) 46 | if bytematch: 47 | size = bytematch[1] 48 | mult = str(bytematch[2]) 49 | size = float(size) 50 | if mult.startswith("k"): 51 | size = size * 1000 52 | elif mult.startswith("M"): 53 | size = size * 1000000 54 | elif mult.startswith("G"): 55 | size = size * 1000000000 56 | elif mult.startswith("P"): 57 | size = size * 1000000000000 58 | except Exception as e: 59 | print("Content site Byte parsing error: ", str(e)) 60 | return DataSize(value=int(size), unit=DataUnits.byte.value) 61 | -------------------------------------------------------------------------------- /tobefair_framework/model/configuration/fairness_metric_configuration.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | from typing import Dict, List 6 | 7 | from pydantic import BaseModel, ValidationError, field_validator 8 | 9 | from tobefair_framework.model.alternate_test_behavior import AlternateTestBehavior 10 | from tobefair_framework.model.composite.identifiable_composite import ( 11 | IdentifiableComposite, 12 | ) 13 | from tobefair_framework.model.configuration.fairness_test_configuration import ( 14 | FAIRnessTestConfiguration, 15 | ) 16 | from tobefair_framework.model.identifier.fairness_metric_id import FAIRnessMetricID 17 | from tobefair_framework.model.identifier.fairness_test_id import FAIRnessTestID 18 | 19 | 20 | class MetricPriority(str, Enum): 21 | Essential = "Essential" 22 | Important = "Important" 23 | Useful = "Useful" 24 | 25 | 26 | class ScoringMechanism(str, Enum): 27 | alternative = "alternative" 28 | cumulative = "cumulative" 29 | 30 | 31 | class FAIRnessMetricConfiguration( 32 | BaseModel, IdentifiableComposite[FAIRnessTestConfiguration] 33 | ): 34 | alternate_test_behavior: AlternateTestBehavior = AlternateTestBehavior.skip 35 | id: FAIRnessMetricID 36 | name: str 37 | priority: MetricPriority 38 | tests: Dict[FAIRnessTestID, FAIRnessTestConfiguration] 39 | scoring_mechanism: ScoringMechanism 40 | score: float = 0 41 | 42 | def get_children(self) -> List[FAIRnessTestConfiguration]: 43 | return list(self.tests.values()) 44 | 45 | @property 46 | def get_id(self) -> FAIRnessMetricID: 47 | return self.id 48 | 49 | @field_validator("alternate_test_behavior") 50 | @classmethod 51 | def from_json(cls, value) -> AlternateTestBehavior: 52 | if isinstance(value, str): 53 | return AlternateTestBehavior._member_map_[value].value 54 | elif isinstance(value, AlternateTestBehavior): 55 | return value 56 | raise ValidationError 57 | -------------------------------------------------------------------------------- /tobefair_framework/model/identifier/fair_principle_id.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from enum import Enum 5 | from typing import Any 6 | 7 | from pydantic import ( 8 | BaseModel, 9 | ValidationError, 10 | ValidationInfo, 11 | model_serializer, 12 | model_validator, 13 | ) 14 | from pydantic.functional_validators import ModelWrapValidatorHandler 15 | 16 | from tobefair_framework.model.identifier.fair_dimension_id import FAIRDimensionID 17 | from tobefair_framework.model.identifier.id import SerialHierarchicalID 18 | 19 | 20 | class FAIRPrincipleID(BaseModel, SerialHierarchicalID[str]): 21 | 22 | principle_id: str 23 | 24 | @property 25 | def raw_value(self) -> str: 26 | return str(self.principle_id) 27 | 28 | def get_parent_id(self) -> FAIRDimensionID: 29 | return FAIRDimensionID(dimension_id=self.raw_value[0]) 30 | 31 | def __hash__(self) -> int: 32 | return hash(self.raw_value) 33 | 34 | @model_serializer 35 | def ser_model(self) -> str: 36 | return self.raw_value 37 | 38 | @model_validator(mode="wrap") 39 | @classmethod 40 | def validator( 41 | cls, values: Any, handler: ModelWrapValidatorHandler, info: ValidationInfo 42 | ): 43 | try: 44 | return handler(values) 45 | except ValidationError: 46 | if isinstance(values, str): 47 | return cls(principle_id=values) 48 | return handler(values) 49 | 50 | 51 | class FAIRPrincipleIDs(Enum): 52 | F1 = FAIRPrincipleID(principle_id="F1") 53 | F2 = FAIRPrincipleID(principle_id="F2") 54 | F3 = FAIRPrincipleID(principle_id="F3") 55 | F4 = FAIRPrincipleID(principle_id="F4") 56 | A1 = FAIRPrincipleID(principle_id="A1") 57 | I1 = FAIRPrincipleID(principle_id="I1") 58 | I2 = FAIRPrincipleID(principle_id="I2") 59 | R1 = FAIRPrincipleID(principle_id="R1") 60 | R1_1 = FAIRPrincipleID(principle_id="R1.1") 61 | R1_2 = FAIRPrincipleID(principle_id="R1.2") 62 | R1_3 = FAIRPrincipleID(principle_id="R1.3") 63 | -------------------------------------------------------------------------------- /tests/evaluators/findability/test_F3_02M_1.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | import json 5 | from unittest import TestCase 6 | 7 | from tests.evaluators.fairness_principle_evaluation_tester import ( 8 | FAIRNESS_CONFIGURATION_FOR_TESTS, 9 | ) 10 | from tobefair_backend.principle_evaluators.identifier_in_metadata_evaluator import ( 11 | IdentifierInMetadataEvaluator, 12 | ) 13 | from tobefair_framework.model.metadata.metadata_record import MetadataRecord 14 | 15 | 16 | class TestF302Metric(TestCase): 17 | def test_f3_02m_1_metadata_identifier_in_metadata(self): 18 | path = "tests/data_for_testing/pangaea-metadata-in-schema.org.json" 19 | with open(path, "r") as file: 20 | text = file.read() 21 | metadata_record = MetadataRecord( 22 | is_machine_retrieved=False, raw_value=json.loads(text) 23 | ) 24 | evaluator = IdentifierInMetadataEvaluator( 25 | fairness_configuration=FAIRNESS_CONFIGURATION_FOR_TESTS 26 | ) 27 | result = evaluator._evaluate_json_ld_contains_metadata_info( 28 | json_ld_metadata=metadata_record.raw_value, 29 | meta_data_identifier="https://doi.pangaea.de/10.1594/PANGAEA.908011", 30 | ) 31 | self.assertTrue(result) 32 | 33 | def test_f3_02m_1_metadata_identifier_not_in_metadata(self): 34 | path = "tests/data_for_testing/pangaea-metadata-in-schema.org.json" 35 | with open(path, "r") as file: 36 | text = file.read() 37 | metadata_record = MetadataRecord( 38 | is_machine_retrieved=False, raw_value=json.loads(text) 39 | ) 40 | evaluator = IdentifierInMetadataEvaluator( 41 | fairness_configuration=FAIRNESS_CONFIGURATION_FOR_TESTS 42 | ) 43 | result = evaluator._evaluate_json_ld_contains_metadata_info( 44 | json_ld_metadata=metadata_record.raw_value, 45 | meta_data_identifier="wrong_url_identifier", 46 | ) 47 | self.assertFalse(result) 48 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Routes } from '@angular/router'; 5 | 6 | import { EnvVarGuard } from '@dwb/to-be-fair'; 7 | 8 | import { ResultComponent } from './result/result.component'; 9 | import { GlossaryComponent } from './glossary/glossary.component'; 10 | import { ExplorerComponent } from './explorer/explorer.component'; 11 | import { DetailsComponent } from './details/details.component'; 12 | import { ToolGlossaryComponent } from './tool-glossary/tool-glossary.component'; 13 | import { UserGuideComponent } from './user-guide/user-guide.component'; 14 | import { ResultReportComponent } from './result-report/result-report.component'; 15 | import { HomeComponent } from './home/home.component'; 16 | 17 | export const routes: Routes = [ 18 | { 19 | path: '', 20 | canActivate: [EnvVarGuard], 21 | children: [ 22 | { 23 | path: 'result', 24 | component: ResultComponent, 25 | title: 'Evaluation result', 26 | }, 27 | { 28 | path: 'explorer', 29 | component: ExplorerComponent, 30 | title: 'Explore results', 31 | }, 32 | { 33 | path: 'details', 34 | component: DetailsComponent, 35 | title: 'Detail results', 36 | }, 37 | { 38 | path: 'glossary', 39 | component: GlossaryComponent, 40 | title: 'Glossary', 41 | }, 42 | { 43 | path: 'tool-glossary', 44 | component: ToolGlossaryComponent, 45 | title: 'Tool Glossary', 46 | }, 47 | { 48 | path: 'result-report', 49 | component: ResultReportComponent, 50 | title: 'Full Report', 51 | }, 52 | { 53 | path: '', 54 | component: HomeComponent, 55 | title: 'Home', 56 | }, 57 | { 58 | path: 'user-guide', 59 | component: UserGuideComponent, 60 | title: 'User Guide', 61 | }, 62 | // { 63 | // path: '**', component: PageNotFoundComponent, // TODO: Wildcard route for a 404 page 64 | // }, 65 | ], 66 | }, 67 | ]; 68 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 IBM Corp. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | import { Component, inject } from '@angular/core'; 5 | import { 6 | Router, 7 | RouterOutlet, 8 | RouterLink, 9 | RouterLinkActive, 10 | } from '@angular/router'; 11 | import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; 12 | import { EvaluationService } from '@dwb/to-be-fair'; 13 | 14 | import { ButtonModule } from 'carbon-components-angular'; 15 | import { LinkButtonComponent } from "../link-button/link-button.component"; 16 | 17 | const badgeSources: string[] = [ 18 | "../assets/badge3.png", 19 | "../assets/badge2.png", 20 | "../assets/badge1.png" 21 | ]; 22 | 23 | @Component({ 24 | selector: 'app-home', 25 | standalone: true, 26 | imports: [ 27 | RouterOutlet, 28 | RouterLink, 29 | RouterLinkActive, 30 | ReactiveFormsModule, 31 | ButtonModule, 32 | LinkButtonComponent 33 | ], 34 | templateUrl: './home.component.html', 35 | styleUrl: './home.component.css', 36 | }) 37 | export class HomeComponent { 38 | public evaluationRequestForm = new FormGroup({ 39 | digitalObjectURI: new FormControl(''), 40 | community: new FormControl(''), 41 | task: new FormControl(''), 42 | }); 43 | 44 | evaluationService: EvaluationService = inject(EvaluationService); 45 | error: string | null | undefined; 46 | 47 | constructor(private router: Router) {} 48 | 49 | submitEvaluationRequest() { 50 | const { digitalObjectURI, community, task } = 51 | this.evaluationRequestForm.value; 52 | this.evaluationService.requestStandalone( 53 | digitalObjectURI ?? '', 54 | community ?? '', 55 | task ?? '', 56 | ); 57 | this.evaluationService.error$.subscribe((error) => { 58 | this.error = error; 59 | }); 60 | this.router.navigate(['/result']); 61 | } 62 | 63 | submitTestEvaluationRequest() { 64 | this.evaluationService.requestStandalone( 65 | '10.5281/zenodo.8255910', '', '', 66 | ); 67 | this.evaluationService.error$.subscribe((error) => { 68 | this.error = error; 69 | }); 70 | this.router.navigate(['/result']); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/data_for_testing/mock_community_metadata_standards.json: -------------------------------------------------------------------------------- 1 | { 2 | "BibTeX": { 3 | "acronym": "BibTeX", 4 | "field_of_science": [], 5 | "id": "bibtex-format", 6 | "identifier": [ 7 | { 8 | "type": "local", 9 | "value": "fuji:m34" 10 | }, 11 | { 12 | "type": "local", 13 | "value": "https://doi.org/10.25504/FAIRsharing.bdf2fe" 14 | }, 15 | { 16 | "type": "homepage", 17 | "value": "http://www.bibtex.org/" 18 | }, 19 | { 20 | "type": "namespace", 21 | "value": "http://clarin-pl.eu/ns/experimental/bibtex" 22 | }, 23 | { 24 | "type": "namespace", 25 | "value": "http://lindat.mff.cuni.cz/ns/experimental/bibtex" 26 | }, 27 | { 28 | "type": "namespace", 29 | "value": "http://repository.clarin.dk/ns/experimental/bibtex" 30 | } 31 | ], 32 | "subject_areas": null, 33 | "urls": [ 34 | "http://www.bibtex.org/", 35 | "http://clarin-pl.eu/ns/experimental/bibtex", 36 | "http://lindat.mff.cuni.cz/ns/experimental/bibtex", 37 | "http://repository.clarin.dk/ns/experimental/bibtex" 38 | ] 39 | }, 40 | "Schema.org": { 41 | "acronym": "schemaorg", 42 | "field_of_science": [ 43 | "sciences" 44 | ], 45 | "id": "schemaorg", 46 | "identifier": [ 47 | { 48 | "type": "local", 49 | "value": "https://doi.org/10.25504/FAIRsharing.hzdzq8" 50 | }, 51 | { 52 | "type": "local", 53 | "value": "msc:m101" 54 | }, 55 | { 56 | "type": "namespace", 57 | "value": "https://schema.org" 58 | }, 59 | { 60 | "type": "namespace", 61 | "value": "http://schema.org" 62 | }, 63 | { 64 | "type": "homepage", 65 | "value": "https://schema.org/docs/schemas.html" 66 | } 67 | ], 68 | "subject_areas": [ 69 | "Multidisciplinary" 70 | ], 71 | "urls": [ 72 | "https://schema.org", 73 | "http://schema.org", 74 | "https://schema.org/docs/documents.html", 75 | "https://schema.org/docs/schemas.html" 76 | ] 77 | } 78 | } -------------------------------------------------------------------------------- /tobefair_backend/principle_evaluators/fairness_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 IBM Corp. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | from typing import ClassVar, List 5 | 6 | from tobefair_backend.constants import FAIRNESS_CONFIGURATION_FILE_PATH 7 | from tobefair_framework.core.configuration.fairness_configuration_file_dao import ( 8 | FAIRnessConfigurationFileDAO, 9 | ) 10 | from tobefair_framework.framework_constants import ALLOW_DUPLICATE_TESTS 11 | from tobefair_framework.model.identifier.fairness_test_id import FAIRnessTestID 12 | 13 | 14 | def basic_function(self, *args, **kwargs): 15 | pass 16 | 17 | 18 | def should_execute_test(test_id: FAIRnessTestID) -> bool: 19 | fairness_configuration = FAIRnessConfigurationFileDAO( 20 | file_path=FAIRNESS_CONFIGURATION_FILE_PATH 21 | ) 22 | test_configuration = fairness_configuration.read_configuration() 23 | test_ids_to_evaluate = test_configuration.get_fairness_test_ids_to_evaluate() 24 | return test_id in test_ids_to_evaluate 25 | 26 | 27 | def fairness_test(test_id: FAIRnessTestID): 28 | def decorator(function): 29 | FAIRnessTestRegistry.define_test(test_id) 30 | if should_execute_test(test_id): 31 | 32 | def wrapper(self, *args, **kwargs): 33 | return function(self, *args, **kwargs) 34 | 35 | return wrapper 36 | return basic_function 37 | 38 | return decorator 39 | 40 | 41 | class FAIRnessTestRegistry: 42 | _defined_tests: ClassVar[List[FAIRnessTestID]] = [] 43 | 44 | @classmethod 45 | def define_test(cls, test_id: FAIRnessTestID): 46 | if cls.test_has_been_defined(test_id) and not ALLOW_DUPLICATE_TESTS: 47 | raise DuplicateFAIRnessTestError(duplicate_test_id=test_id) 48 | cls._defined_tests += [test_id] 49 | 50 | @classmethod 51 | def test_has_been_defined(cls, test_id: FAIRnessTestID) -> bool: 52 | return test_id in cls._defined_tests 53 | 54 | 55 | class DuplicateFAIRnessTestError(Exception): 56 | def __init__(self, duplicate_test_id: FAIRnessTestID) -> None: 57 | error_message = ( 58 | f"FAIRness test with ID {duplicate_test_id.value} declared twice" 59 | ) 60 | super().__init__(error_message) 61 | -------------------------------------------------------------------------------- /tobefair-frontend/src/app/home/home.component.css: -------------------------------------------------------------------------------- 1 | .welcome { 2 | padding: 48px; 3 | margin-top: 48px; 4 | display: flex; 5 | flex-direction: column; 6 | gap: 40px; 7 | min-width: fit-content; 8 | } 9 | .title-block{ 10 | display: flex; 11 | flex-direction: column; 12 | gap: 8px; 13 | } 14 | .grid-container { 15 | display: grid; 16 | min-height: 100vh; 17 | grid-template-columns: 1fr 1fr; 18 | } 19 | #badge-container { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | background-color: #EDF5FF; 24 | padding-bottom: 48px; 25 | } 26 | #execute-container { 27 | width: 100%; 28 | max-width: 100%; 29 | display: flex; 30 | justify-content: space-between; 31 | gap: 8px; 32 | min-width: fit-content; 33 | } 34 | 35 | #example-button { 36 | background-color: transparent; 37 | background-repeat:no-repeat; 38 | border: none; 39 | cursor:pointer; 40 | overflow: hidden; 41 | color: #0062fe; 42 | text-decoration: underline; 43 | padding: 0; 44 | height: fit-content; 45 | } 46 | 47 | .form-container { 48 | display: flex; 49 | flex-direction: column; 50 | gap: 8px; 51 | } 52 | 53 | .form-container input { 54 | width: 100%; 55 | margin: 0px; 56 | } 57 | 58 | h2 { 59 | font-weight: normal; 60 | margin-block-start: 0em; 61 | } 62 | 63 | h4 { 64 | margin-bottom: 16px; 65 | } 66 | 67 | input { 68 | border-radius: 0%; 69 | border: 1px solid lightgray; 70 | font-size: 14px; 71 | padding: 12px 12px; 72 | margin-top: 8px 73 | /* width: 97.5%; */ 74 | } 75 | 76 | input, 77 | select, 78 | textarea { 79 | box-sizing: border-box; 80 | -moz-box-sizing: border-box; 81 | -webkit-box-sizing: border-box; 82 | } 83 | 84 | ::placeholder { 85 | color: lightgray; 86 | opacity: 1; /* Firefox */ 87 | } 88 | 89 | label { 90 | color: gray; 91 | } 92 | 93 | a { 94 | color: black; 95 | text-decoration: none; 96 | } 97 | 98 | a:hover { 99 | cursor: pointer; 100 | color: #0062fe; 101 | } 102 | 103 | #gray-line { 104 | background-color: #E0E0E0; 105 | height: 1px; 106 | width: 100%; 107 | } 108 | 109 | .black-line { 110 | background-color: black; 111 | height: 1px; 112 | width: 100%; 113 | } 114 | 115 | --------------------------------------------------------------------------------