Skip to content

Commit d49034c

Browse files
authored
Merge pull request #247 from IFCA-Advanced-Computing/synergy_contributions
Synergy contributions
2 parents e31286b + 976660a commit d49034c

18 files changed

+738
-104
lines changed

.github/workflows/pre-commit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ jobs:
1111
steps:
1212
- uses: actions/checkout@v3
1313
- uses: actions/setup-python@v3
14-
- uses: pre-commit/[email protected].0
14+
- uses: pre-commit/[email protected].1

api/rda.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import glob
12
import importlib
23
import logging
34
import os
@@ -8,7 +9,7 @@
89
from connexion import NoContent
910

1011
import api.utils as ut
11-
from api.evaluator import Evaluator
12+
from api import evaluator
1213
from fair import app_dirname, load_config
1314

1415
logging.basicConfig(
@@ -38,10 +39,12 @@ def wrapper(body, **kwargs):
3839
# Get the identifiers through a search query
3940
ids = [item_id]
4041
# FIXME oai-pmh should be no different
42+
downstream_logger = evaluator.logger
4143
if repo not in ["oai-pmh"]:
4244
try:
4345
logger.debug("Trying to import plugin from plugins.%s.plugin" % (repo))
4446
plugin = importlib.import_module("plugins.%s.plugin" % (repo), ".")
47+
downstream_logger = plugin.logger
4548
except Exception as e:
4649
logger.error(str(e))
4750
return str(e), 400
@@ -54,25 +57,72 @@ def wrapper(body, **kwargs):
5457
logger.error(str(e))
5558
return str(e), 400
5659

60+
# Set handler for evaluator logs
61+
evaluator_handler = ut.EvaluatorLogHandler()
62+
downstream_logger.addHandler(evaluator_handler)
63+
5764
# Collect FAIR checks per metadata identifier
5865
result = {}
5966
exit_code = 200
6067
for item_id in ids:
6168
# FIXME oai-pmh should be no different
6269
if repo in ["oai-pmh"]:
63-
eva = Evaluator(item_id, oai_base, lang)
70+
eva = evaluator.Evaluator(item_id, oai_base, lang)
6471
else:
6572
eva = plugin.Plugin(item_id, oai_base, lang)
6673
_result, _exit_code = wrapped_func(body, eva=eva)
74+
logger.debug(
75+
"Raw result returned for indicator ID '%s': %s" % (item_id, _result)
76+
)
6777
result[item_id] = _result
6878
if _exit_code != 200:
6979
exit_code = _exit_code
7080

81+
# Append evaluator logs to the final results
82+
result["evaluator_logs"] = evaluator_handler.logs
83+
logger.debug("Evaluator logs appended through 'evaluator_logs' property")
84+
7185
return result, exit_code
7286

7387
return wrapper
7488

7589

90+
def endpoints(plugin=None, plugins_path="plugins"):
91+
plugins_with_endpoint = []
92+
links = []
93+
94+
# Get the list of plugins
95+
modules = glob.glob(os.path.join(app_dirname, plugins_path, "*"))
96+
plugins_list = [
97+
os.path.basename(folder) for folder in modules if os.path.isdir(folder)
98+
]
99+
100+
# Obtain endpoint from each plugin's config
101+
for plug in plugins_list:
102+
config = load_config(plugin=plug, fail_if_no_config=False)
103+
endpoint = config.get("Generic", "endpoint", fallback="")
104+
if not endpoint:
105+
logger.debug(
106+
"Plugin's config does not contain 'Generic:endpoint' section: %s" % plug
107+
)
108+
logger.warning(
109+
"Could not get (meta)data endpoint from plugin's config: %s " % plug
110+
)
111+
else:
112+
logger.debug("Obtained endpoint for plugin '%s': %s" % (plug, endpoint))
113+
links.append(endpoint)
114+
plugins_with_endpoint.append(plug)
115+
# Create a dict with all the found endpoints
116+
enp = dict(zip(plugins_with_endpoint, links))
117+
# If the plugin is given then only returns a message
118+
if plugin:
119+
try:
120+
return enp[plugin]
121+
except:
122+
return (enp, 404)
123+
return enp
124+
125+
76126
@load_evaluator
77127
def rda_f1_01m(body, eva):
78128
try:

api/utils.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
1616

1717

18+
class EvaluatorLogHandler(logging.Handler):
19+
def __init__(self, level=logging.DEBUG):
20+
self.level = level
21+
self.logs = []
22+
23+
def handle(self, record):
24+
self.logs.append("[%s] %s" % (record.levelname, record.msg))
25+
26+
1827
def get_doi_str(doi_str):
1928
doi_to_check = re.findall(
2029
r"10[\.-]+.[\d\.-]+/[\w\.-]+[\w\.-]+/[\w\.-]+[\w\.-]", doi_str
@@ -834,8 +843,10 @@ def resolve_handle(handle_id):
834843
835844
Returns:
836845
"""
837-
resolves = False
838-
endpoint = urljoin("https://hdl.handle.net/api/", "handles/%s" % handle_id)
846+
handle_id_normalized = idutils.normalize_doi(handle_id)
847+
endpoint = urljoin(
848+
"https://hdl.handle.net/api/", "handles/%s" % handle_id_normalized
849+
)
839850
headers = {"Content-Type": "application/json"}
840851
r = requests.get(endpoint, verify=False, headers=headers)
841852
if not r.ok:
@@ -844,9 +855,10 @@ def resolve_handle(handle_id):
844855
r.status_code,
845856
)
846857
raise Exception(msg)
847-
848858
json_data = r.json()
849859
response_code = json_data.get("responseCode", -1)
860+
861+
resolves = False
850862
if response_code == 1:
851863
resolves = True
852864
msg = "Handle and associated values found (HTTP 200 OK)"
@@ -978,3 +990,15 @@ def check_fairsharing_abbreviation(fairlist, abreviation):
978990
if abreviation == standard["attributes"]["abbreviation"]:
979991
return (100, "Your metadata standard appears in Fairsharing")
980992
return (0, "Your metadata standard has not been found in Fairsharing")
993+
994+
995+
def check_ror(ror):
996+
response = requests.get("https://api.ror.org/organizations/" + ror)
997+
998+
rordict = response.json()
999+
name = rordict["name"]
1000+
1001+
if response.ok:
1002+
return (True, name)
1003+
else:
1004+
return (False, "")

docs/How to use the epos plugin.md

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ The FAIR EVA API needs to running in the background or in an individual terminal
2020
```
2121

2222
### 3. Test FAIR EVA
23-
For the sake of simplificity, we will use the metadata identifier `7c9dfb3c-7db0-4424-8843-ada2143b00a0` that exists in the current [DT-GEO prototype](https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1). FAIR EVA comes with a CLI that simplies the task of making requests to the API. We will use it in a different terminal (terminal #2) from the one that launched the API in the previous step:
23+
For the sake of simplificity, we will use the metadata identifier `d4101e2f-c1b9-4fde-a4d1-d79a26d5d23a` that exists in the current [DT-GEO prototype](https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1). FAIR EVA comes with a CLI that simplies the task of making requests to the API. We will use it in a different terminal (terminal #2) from the one that launched the API in the previous step:
2424

2525
```
26-
(terminal #2) python3 scripts/fair-eva.py --id 7c9dfb3c-7db0-4424-8843-ada2143b00a0 --plugin epos --repository https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1
26+
(terminal #2) python3 scripts/fair-eva.py --id d4101e2f-c1b9-4fde-a4d1-d79a26d5d23a --plugin epos -j
2727
```
2828

2929
The previous command is similar to the following `curl` command:
3030

3131
```
3232
(terminal #2) curl -H "accept: application/json"\
3333
-H "Content-Type: application/json" \
34-
-d '{"id":"7c9dfb3c-7db0-4424-8843-ada2143b00a0","lang":"es","oai_base": "https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1","repo":"epos"}'\
34+
-d '{"id":"d4101e2f-c1b9-4fde-a4d1-d79a26d5d23a","lang":"es","oai_base": "https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1","repo":"epos"}'\
3535
-X POST "http://localhost:9090/v1.0/rda/rda_all"
3636
```
3737

@@ -47,7 +47,7 @@ In terminal 2, instead of using the previous comand use:
4747
```
4848
(terminal #2) curl -H "accept: application/json"\
4949
-H "Content-Type: application/json"\
50-
-d '{"id":"7c9dfb3c-7db0-4424-8843-ada2143b00a0","lang":"es","oai_base": "https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1","repo":"epos"}' \
50+
-d '{"id":"d4101e2f-c1b9-4fde-a4d1-d79a26d5d23a","lang":"es","oai_base": "https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1","repo":"epos"}' \
5151
-X POST "http://localhost:9090/v1.0/rda/rda_f2_01m"
5252
```
5353
Same as before this is an example, you can change the q parameter to whatever you want to search. This will return the id of all the results found.
@@ -56,10 +56,19 @@ To make sure its the one you are looking for you can make a curl to the API with
5656
Now take a look at terminal 1, it will display a table with important findability-related terms, one of them is the title, so you can make sure the item is the one that you want,
5757
(If the table displays a lot of ... items try to make the window wider and retry the test)
5858

59+
#### 2. Use the `--search` optional argument from the fair-eva.py script
5960

60-
#### 2. Connecting directly to the EPOS API
61+
A simple way to get the UUID is to use the searcher option to conect to the EPOS API. In terminal 2 just use the command:
6162

62-
You can perform a curl to the EPOS API to get your UUID. Yhe process is the same as before
63+
```
64+
(terminal #2) python3 scripts/fair-eva.py --search SVO --plugin epos -j
65+
```
66+
67+
Then you will select an index and the evaluation will be performed directly.
68+
69+
#### 3. Connecting directly to the EPOS API
70+
71+
You can perform a curl to the EPOS API to get your UUID. The process is the same as before
6372
```
6473
curl -X 'GET' \
6574
'https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1/resources/search?q=SVO' \
@@ -118,25 +127,34 @@ You may get more than one item, make sure you copy the UUID of the item you are
118127
The API path can be modified in order to trigger the evaluation of a single FAIR check. This is done through the `--api-endpoint` option as follows:
119128

120129
```
121-
python3 scripts/fair-eva.py --id 7c9dfb3c-7db0-4424-8843-ada2143b00a0 --plugin epos --repository https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1 --api-endpoint http://localhost:9090/v1.0/rda/rda_f1_01m
130+
python3 scripts/fair-eva.py --id d4101e2f-c1b9-4fde-a4d1-d79a26d5d23a --plugin epos --repository https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1 --api-endpoint http://localhost:9090/v1.0/rda/rda_f1_01m
122131
```
123132

124133
This command will return the evaluation of the RDA-F1-01M indicator.
125134

126135
### Scores
127-
To get a clear view of the scores the CLI has 2 extra parameters that print the punctuation of the item in the distict catergories.
136+
To get a clear view of the scores the CLI has an extra parameter that print the punctuation of the item in the distict catergories.
128137

129-
You can add -s to get the points in each of the FAIR catergories and the total score.
138+
You can add --totals to get the points in each of the FAIR catergories and the total score.
130139
```
131-
(terminal #2) python3 scripts/fair-eva.py --id 7c9dfb3c-7db0-4424-8843-ada2143b00a0 --plugin epos --repository https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1 -s
140+
(terminal #2) python3 scripts/fair-eva.py --id d4101e2f-c1b9-4fde-a4d1-d79a26d5d23a --plugin epos --repository https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1 --totals
132141
```
133-
Or you can add -fs to get the points in each of the different checks
134-
the total score.
135-
```
136-
(terminal #2) python3 scripts/fair-eva.py --id 7c9dfb3c-7db0-4424-8843-ada2143b00a0 --plugin epos --repository https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1 -fs
137-
```
138-
You can also use them both together. Note that the points are not the basic average of the tests, because each test has a different weight.
142+
Note that the points are the pondered average of the tests, because each test has a different weight.
143+
144+
### Configuration through config.ini.
145+
There are some tests whose results depend on things outside of the metadata given by the EPOS API so their result depends on a configuration parameter. These parameters are stored in the file 'config.ini' you can change these parameters to change some results. WARNING a lot of parameters are essential for the tool to work. If the parameter you are interested in changing doesn't appear on the following list you probably shouldn't change it:
146+
147+
1. supportted_data_formats: The formats that are considered standard.
148+
2. terms_access_protocols: The list of accepted protocols to access (meta)data.
149+
3. metadata_access_manual: a guide on how to access the metadata manually without the tool.
150+
4. data_access_manual: A guide on how to access data manually
151+
5. terms data model*: The model of the data you are checking
152+
6. metadata_standard: The standard in which the metadata is based on
153+
7. metadata_persistance*: This is the policy of the persistence of the metadata.
154+
8. metadata_authentication*: The authentication or autorisation protocols provided by the platform
155+
9. [fairsharing]username and password: If you want to refresh the fairsharing list, you can use your fairsharing username and password
139156

157+
There are some parameters with * this mean that at the time of writing we have not found (mainly becaiuse it doesn't exist at the moment or is not clear) a good value.
140158
## Alternative ways to use the FAIR EVA
141159
There are two alternatives if you do not want to install FAIR EVA.
142160

fair-api.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,43 @@ paths:
4040
schema:
4141
$ref: "#/components/schemas/Error"
4242

43+
/endpoints:
44+
x-indicator: False
45+
get:
46+
summary: Return all the possible endpoints in a JSON format
47+
tags:
48+
- RDA indicators
49+
operationId: api.rda.endpoints
50+
parameters:
51+
- in: query
52+
name: plugin
53+
schema:
54+
type: string
55+
required: False
56+
description: The plugin you want the enpoint for
57+
responses:
58+
'200':
59+
description: Expected response to a valid request
60+
content:
61+
application/json:
62+
schema:
63+
type: string
64+
'404':
65+
description: Response to a wrong plugin request
66+
content:
67+
application/json:
68+
schema:
69+
type: string
70+
'400':
71+
description: Null response
72+
default:
73+
description: unexpected error
74+
content:
75+
application/json:
76+
schema:
77+
$ref: "#/components/schemas/Error"
78+
79+
4380
/rda/rda_all:
4481
x-indicator: False
4582
post:
@@ -1452,6 +1489,7 @@ paths:
14521489

14531490
components:
14541491
schemas:
1492+
14551493
Test:
14561494
required:
14571495
- name

fair.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
app_dirname = os.path.dirname(os.path.abspath(__file__))
2020

2121

22-
def load_config(plugin=None):
22+
def load_config(plugin=None, fail_if_no_config=True):
2323
config = configparser.ConfigParser()
2424
if plugin:
2525
config_file = os.path.join(app_dirname, "plugins/%s/config.ini" % plugin)
@@ -31,6 +31,10 @@ def load_config(plugin=None):
3131
try:
3232
config.read_file(open(config_file))
3333
logging.debug("Main configuration successfully loaded: %s" % config_file)
34+
except FileNotFoundError as e:
35+
logging.error("Could not load config file: %s" % str(e))
36+
if fail_if_no_config:
37+
raise (e)
3438
except configparser.MissingSectionHeaderError as e:
3539
message = "Could not find main config file: %s" % config_file
3640
logging.error(message)
@@ -49,4 +53,4 @@ def load_config(plugin=None):
4953
arguments={"title": "FAIR evaluator Example"},
5054
resolver=RestyResolver("api"),
5155
)
52-
app.run(port=8080)
56+
app.run(port=9090)

plugins/digital_csic/config.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
[Generic]
2+
endpoint='http://digital.csic.es/dspace-oai/request'
13
[digital_csic]
24
db_host =
35
db_port =

plugins/epos/config.ini

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
[Generic]
22
doi_url = https://doi.org/
3-
43
# Relative path to the API config file
54
api_config = fair-api.yaml
6-
5+
endpoint=https://ics-c.epos-ip.org/development/k8s-epos-deploy/dt-geo/api/v1
76
[local]
87
only_local = false
98
repo = digital_csic
@@ -143,19 +142,36 @@ terms_data_model = []
143142
metadata_standard = ['DCAT']
144143

145144

145+
#Policy of metadata persistence
146+
metadata_persistence = []
147+
148+
#Authentication for EPOS
149+
metadata_authentication = []
150+
151+
#terms that use vocabularies and vocabularies used
152+
dict_vocabularies= {'ROR': 'https://ror.org/', 'PIC': 'https://ec.europa.eu/info/funding-tenders/opportunities/portal/screen/how-to-participate/participant-register', 'imtypes': 'https://www.iana.org/assignments/media-types/media-types.xhtml', 'TRL': 'TRL', 'temporal': 'https://www.iso.org/iso-8601-date-and-time-format.html', 'Rolecode': 'Rolecode', 'spdx': 'https://spdx.org/licenses/', 'ORCID': 'https://orcid.org/'}
153+
154+
terms_vocabularies=[['identifiers','relatedDataProducts'],
155+
['',''],
156+
['availableFormats',''],
157+
['',''],
158+
['temporalCoverage','relatedDataProducts'],#no temporal metatdata
159+
['',''],
160+
['license',''],
161+
['contactPoints','relatedDataProducts']]
162+
163+
146164
[fairsharing]
147165
# username and password
148166
username = ['']
149167

150168
password = ['']
151-
#Path is the folder path ehere the netadata or fomats is stored
152-
#Or if the username or password is given is what you are looking in
153-
metadata_path = ['static/fairsharing_metadata_standards140224.json']
154169

155-
formats_path = ['static/fairsharing_formats260224.txt']
170+
#_path is variable that stores the path to the file in which the fairsharing-approved metadatata standards or formasts are stored
156171

172+
metadata_path = ['static/fairsharing_metadata_standards20240214.json']
157173

158-
fairsharing_formats_path = ['static/fairsharing_formats150224.json']
174+
formats_path = ['static/fairsharing_formats20240226.txt']
159175

160176

161177

0 commit comments

Comments
 (0)